diff --git a/redisson/src/main/java/org/redisson/RedissonMapCache.java b/redisson/src/main/java/org/redisson/RedissonMapCache.java
index c664fed29..4bb361f87 100644
--- a/redisson/src/main/java/org/redisson/RedissonMapCache.java
+++ b/redisson/src/main/java/org/redisson/RedissonMapCache.java
@@ -15,16 +15,9 @@
  */
 package org.redisson;
 
-import java.math.BigDecimal;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
+import io.netty.buffer.ByteBuf;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.FutureListener;
 import org.redisson.api.MapOptions;
 import org.redisson.api.RFuture;
 import org.redisson.api.RMapCache;
@@ -58,9 +51,15 @@ import org.redisson.command.CommandAsyncExecutor;
 import org.redisson.connection.decoder.MapGetAllDecoder;
 import org.redisson.eviction.EvictionScheduler;
 
-import io.netty.buffer.ByteBuf;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.FutureListener;
+import java.math.BigDecimal;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
  * <p>Map-based cache with ability to set TTL for each entry via
@@ -83,134 +82,163 @@ import io.netty.util.concurrent.FutureListener;
  */
 public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCache<K, V> {
 
-    public RedissonMapCache(EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, 
-            String name, RedissonClient redisson, MapOptions<K, V> options) {
+    private final int maxSize;
+
+    public RedissonMapCache(EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor,
+                            String name, RedissonClient redisson, MapOptions<K, V> options) {
         super(commandExecutor, name, redisson, options);
         evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName(), getExpiredChannelName());
+
+        if (options != null) {
+            this.maxSize = options.getMaxSize();
+        } else {
+            this.maxSize = 0;
+        }
     }
 
-    public RedissonMapCache(Codec codec, EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor, 
-            String name, RedissonClient redisson, MapOptions<K, V> options) {
+    public RedissonMapCache(Codec codec, EvictionScheduler evictionScheduler, CommandAsyncExecutor commandExecutor,
+                            String name, RedissonClient redisson, MapOptions<K, V> options) {
         super(codec, commandExecutor, name, redisson, options);
         evictionScheduler.schedule(getName(), getTimeoutSetName(), getIdleSetName(), getExpiredChannelName());
+
+        if (options != null) {
+            this.maxSize = options.getMaxSize();
+        } else {
+            this.maxSize = 0;
+        }
     }
-    
+
     @Override
     public RFuture<Boolean> containsKeyAsync(Object key) {
         checkKey(key);
-        
+
         return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
-                "local value = redis.call('hget', KEYS[1], ARGV[2]); " +
-                "local expireDate = 92233720368547758; " +
-                "if value ~= false then " +
-                      "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-                    + "if expireDateScore ~= false then "
-                        + "expireDate = tonumber(expireDateScore) "
-                    + "end; "
-                    + "local t, val = struct.unpack('dLc0', value); "
-                    + "if t ~= 0 then "
-                        + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                        + "if expireIdle ~= false then "
-                            + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
-                                 + "local value = struct.pack('dLc0', t, string.len(val), val); "
-                                 + "redis.call('hset', KEYS[1], ARGV[2], value); "
-                                 + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); "
-                            + "end; "
-                            + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                        + "end; "
-                    + "end; "
-                    + "if expireDate <= tonumber(ARGV[1]) then "
-                        + "return 0;"
-                    + "end; "
-                    + "return 1;" +
+        "local value = redis.call('hget', KEYS[1], ARGV[2]);" +
+                "local expireDate = 92233720368547758;" +
+                "if value ~= false then" +
+                "" +
+                "    local maxSize = tonumber(ARGV[3]);" +
+                "    if maxSize ~= 0 then" +
+                "        redis.call('zadd', KEYS[4], tonumber(ARGV[1]), ARGV[2]);" +
+                "    end;" +
+                "" +
+                "    local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]);" +
+                "    if expireDateScore ~= false then" +
+                "        expireDate = tonumber(expireDateScore)" +
+                "    end;" +
+                "    local t, val = struct.unpack('dLc0', value);" +
+                "    if t ~= 0 then" +
+                "        local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]);" +
+                "        if expireIdle ~= false then" +
+                "            if tonumber(expireIdle) > tonumber(ARGV[1]) then" +
+                "                local value = struct.pack('dLc0', t, string.len(val), val);" +
+                "                redis.call('hset', KEYS[1], ARGV[2], value);" +
+                "                redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]);" +
+                "            end;" +
+                "            expireDate = math.min(expireDate, tonumber(expireIdle))" +
+                "        end;" +
+                "    end;" +
+                "    if expireDate <= tonumber(ARGV[1]) then" +
+                "        return 0;" +
+                "    end;" +
+                "    return 1;" +
                 "end;" +
                 "return 0; ",
-               Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), 
-               System.currentTimeMillis(), encodeMapKey(key));
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getLastAccessTimeSetNameByKey(key)),
+                System.currentTimeMillis(), encodeMapKey(key), maxSize);
     }
 
     @Override
     public RFuture<Boolean> containsValueAsync(Object value) {
         checkValue(value);
-        
+
         return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN,
-                        "local s = redis.call('hgetall', KEYS[1]); "
-                        + "for i, v in ipairs(s) do "
-                            + "if i % 2 == 0 then "
-                              + "local t, val = struct.unpack('dLc0', v); "
-                              + "if ARGV[2] == val then "
-                                  + "local key = s[i-1];" +
-                                    "local expireDate = 92233720368547758; " +
-                                    "local expireDateScore = redis.call('zscore', KEYS[2], key); "
-                                    + "if expireDateScore ~= false then "
-                                        + "expireDate = tonumber(expireDateScore) "
-                                    + "end; "
-                                    + "if t ~= 0 then "
-                                        + "local expireIdle = redis.call('zscore', KEYS[3], key); "
-                                        + "if expireIdle ~= false then "
-                                            + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
-                                                + "local value = struct.pack('dLc0', t, string.len(val), val); "
-                                                + "redis.call('hset', KEYS[1], key, value); "
-                                                + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); "
-                                            + "end; "
-                                            + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                                        + "end; "
-                                    + "end; "
-                                    + "if expireDate <= tonumber(ARGV[1]) then "
-                                        + "return 0;"
-                                    + "end; "
-                                    + "return 1; "
-                              + "end; "
-                            + "end; "
-                       + "end;" +
-                     "return 0;",
-                 Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName()), System.currentTimeMillis(), encodeMapValue(value));
+        "local s = redis.call('hgetall', KEYS[1]);" +
+                "for i, v in ipairs(s) do" +
+                "    if i % 2 == 0 then" +
+                "        local t, val = struct.unpack('dLc0', v);" +
+                "        if ARGV[2] == val then" +
+                "            local key = s[i - 1];" +
+                "" +
+                "            local maxSize = tonumber(ARGV[3]);" +
+                "            if maxSize ~= 0 then" +
+                "                redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key);" +
+                "            end;" +
+                "" +
+                "            local expireDate = 92233720368547758;" +
+                "            local expireDateScore = redis.call('zscore', KEYS[2], key);" +
+                "            if expireDateScore ~= false then" +
+                "                expireDate = tonumber(expireDateScore)" +
+                "            end;" +
+                "            if t ~= 0 then" +
+                "                local expireIdle = redis.call('zscore', KEYS[3], key);" +
+                "                if expireIdle ~= false then" +
+                "                    if tonumber(expireIdle) > tonumber(ARGV[1]) then" +
+                "                        local value = struct.pack('dLc0', t, string.len(val), val);" +
+                "                        redis.call('hset', KEYS[1], key, value);" +
+                "                        redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key);" +
+                "                    end;" +
+                "                    expireDate = math.min(expireDate, tonumber(expireIdle))" +
+                "                end;" +
+                "            end;" +
+                "            if expireDate <= tonumber(ARGV[1]) then" +
+                "                return 0;" +
+                "            end;" +
+                "            return 1;" +
+                "        end;" +
+                "    end;" +
+                "end;" +
+                "return 0;",
+                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()),
+                System.currentTimeMillis(), encodeMapValue(value), maxSize);
     }
 
     @Override
     protected RFuture<Map<K, V>> getAllOperationAsync(Set<K> keys) {
-        List<Object> args = new ArrayList<Object>(keys.size() + 1);
+        List<Object> args = new ArrayList<Object>(keys.size() + 2);
         args.add(System.currentTimeMillis());
+        args.add(maxSize);
         args.addAll(keys);
 
-        return commandExecutor.evalWriteAsync(getName(), codec, new RedisCommand<Map<Object, Object>>("EVAL", new MapGetAllDecoder(args, 1), 7, ValueType.MAP_KEY, ValueType.MAP_VALUE),
-                        "local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores');" +
-                        "local currentTime = tonumber(table.remove(ARGV, 1)); " // index is the first parameter
-                      + "local hasExpire = #expireHead == 2 and tonumber(expireHead[2]) <= currentTime; "
-                      + "local map = redis.call('hmget', KEYS[1], unpack(ARGV)); "
-                      + "for i = #map, 1, -1 do "
-                          + "local value = map[i]; "
-                          + "if value ~= false then "
-                              + "local key = ARGV[i]; "
-                              + "local t, val = struct.unpack('dLc0', value); "
-                              + "map[i] = val; "
-
-                              + "if hasExpire then "
-                                  + "local expireDate = redis.call('zscore', KEYS[2], key); "
-                                  + "if expireDate ~= false and tonumber(expireDate) <= currentTime then "
-                                      + "map[i] = false; "
-                                  + "end; "
-                              + "end; "
-
-                              + "if t ~= 0 then "
-                                  + "local expireIdle = redis.call('zscore', KEYS[3], key); "
-                                  + "if expireIdle ~= false then "
-                                      + "if tonumber(expireIdle) > currentTime then "
-                                          + "local value = struct.pack('dLc0', t, string.len(val), val); "
-                                          + "redis.call('hset', KEYS[1], key, value); "
-                                          + "redis.call('zadd', KEYS[3], t + currentTime, key); "
-                                      + "else "
-                                          + "map[i] = false; "
-                                      + "end; "
-                                  + "end; "
-                              + "end; "
-
-                          + "end; "
-                      + "end; "
-                      + "return map;",
-                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName()), args.toArray());
+        return commandExecutor.evalWriteAsync(getName(), codec, new RedisCommand<Map<Object, Object>>("EVAL", new MapGetAllDecoder(args, 2), 7, ValueType.MAP_KEY, ValueType.MAP_VALUE),
+            "local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores');" +
+            "local currentTime = tonumber(table.remove(ARGV, 1));" + // index is the first parameter
+            "local maxSize = tonumber(table.remove(ARGV, 1));" + // index is the first parameter
+            "local hasExpire = #expireHead == 2 and tonumber(expireHead[2]) <= currentTime;" +
+            "local map = redis.call('hmget', KEYS[1], unpack(ARGV));" +
+            "for i = #map, 1, -1 do" +
+            "    local value = map[i];" +
+            "    if value ~= false then" +
+            "        local key = ARGV[i];" +
+            "        local t, val = struct.unpack('dLc0', value);" +
+            "        map[i] = val;" +
+            "        if maxSize ~= 0 then" +
+            "            redis.call('zadd', KEYS[4], currentTime, key);" +
+            "        end;" +
+            "        if hasExpire then" +
+            "            local expireDate = redis.call('zscore', KEYS[2], key);" +
+            "            if expireDate ~= false and tonumber(expireDate) <= currentTime then" +
+            "                map[i] = false;" +
+            "            end;" +
+            "        end;" +
+            "        if t ~= 0 then" +
+            "            local expireIdle = redis.call('zscore', KEYS[3], key);" +
+            "            if expireIdle ~= false then" +
+            "                if tonumber(expireIdle) > currentTime then" +
+            "                    local value = struct.pack('dLc0', t, string.len(val), val);" +
+            "                    redis.call('hset', KEYS[1], key, value);" +
+            "                    redis.call('zadd', KEYS[3], t + currentTime, key);" +
+            "                else" +
+            "                    map[i] = false;" +
+            "                end;" +
+            "            end;" +
+            "        end;" +
+            "    end;" +
+            "end;" +
+            "return map;",
+            Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()), args.toArray());
     }
-    
+
     @Override
     public V putIfAbsent(K key, V value, long ttl, TimeUnit ttlUnit) {
         return get(putIfAbsentAsync(key, value, ttl, ttlUnit));
@@ -262,68 +290,93 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
         }
 
         RFuture<V> future = commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
-        		  "local insertable = false; "
-	            + "local value = redis.call('hget', KEYS[1], ARGV[5]); "
-	            + "if value == false then "
-	            	+ "insertable = true; "
-	        	+ "else "
-		        		+ "local t, val = struct.unpack('dLc0', value); "
-		                + "local expireDate = 92233720368547758; "
-		                + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); "
-		                + "if expireDateScore ~= false then "
-		                    + "expireDate = tonumber(expireDateScore) "
-		                + "end; "
-		                + "if t ~= 0 then "
-		                    + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); "
-		                    + "if expireIdle ~= false then "
-		                        + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-		                    + "end; "
-		                + "end; "
-		                + "if expireDate <= tonumber(ARGV[1]) then "
-		                    + "insertable = true; "
-		                + "end; "        	
-	        		+ "end; "
-	        		
-				+ "if insertable == true then "
-					// ttl
-					+ "if tonumber(ARGV[2]) > 0 then "
-						+ "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); "
-					+ "else "
-						+ "redis.call('zrem', KEYS[2], ARGV[5]); "
-					+ "end; "
-						
-					// idle
-					+ "if tonumber(ARGV[3]) > 0 then "
-						+ "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); "
-					+ "else "
-						+ "redis.call('zrem', KEYS[3], ARGV[5]); "
-					+ "end; "
-					
-					// value
-					+ "local val = struct.pack('dLc0', tonumber(ARGV[4]), string.len(ARGV[6]), ARGV[6]); "
-					+ "redis.call('hset', KEYS[1], ARGV[5], val); "
-					
-                    + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); "
-                    + "redis.call('publish', KEYS[4], msg); "
-					
-					+ "return nil;"
-				+ "else "
-					+ "local t, val = struct.unpack('dLc0', value); "
-					+ "redis.call('zadd', KEYS[3], t + ARGV[1], ARGV[5]); "
-					+ "return val;"
-				+ "end; ",
-				Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key)), 
-				System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
+                "local insertable = false; "
+                        + "local value = redis.call('hget', KEYS[1], ARGV[5]); "
+                            + "if value == false then "
+                            + "insertable = true; "
+                        + "else "
+                            + "local t, val = struct.unpack('dLc0', value); "
+                            + "local expireDate = 92233720368547758; "
+                            + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); "
+                            + "if expireDateScore ~= false then "
+                                + "expireDate = tonumber(expireDateScore) "
+                            + "end; "
+                            + "if t ~= 0 then "
+                                + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); "
+                                + "if expireIdle ~= false then "
+                                    + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                                + "end; "
+                            + "end; "
+                            + "if expireDate <= tonumber(ARGV[1]) then "
+                                + "insertable = true; "
+                            + "end; "
+                        + "end; "
+
+                        + "if insertable == true then "
+                            // ttl
+                            + "if tonumber(ARGV[2]) > 0 then "
+                                + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); "
+                            + "else "
+                                + "redis.call('zrem', KEYS[2], ARGV[5]); "
+                            + "end; "
+
+                            // idle
+                            + "if tonumber(ARGV[3]) > 0 then "
+                                + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); "
+                            + "else "
+                                + "redis.call('zrem', KEYS[3], ARGV[5]); "
+                            + "end; "
+
+                            // last access time
+                            + "local maxSize = tonumber(ARGV[7]);" +
+                            "if maxSize ~= 0 then" +
+                            "    local currentTime = tonumber(ARGV[1]);" +
+                            "    local lastAccessTimeSetName = KEYS[5];" +
+                            "    redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]);" +
+                            "    local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" +
+                            "    if cacheSize >= maxSize then" +
+                            "        local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" +
+                            "        for index, lruItem in ipairs(lruItems) do" +
+                            "            if lruItem then" +
+                            "                local lruItemValue = redis.call('hget', KEYS[1], lruItem);" +
+                            "                redis.call('hdel', KEYS[1], lruItem);" +
+                            "                redis.call('zrem', KEYS[2], lruItem);" +
+                            "                redis.call('zrem', KEYS[3], lruItem);" +
+                            "                redis.call('zrem', lastAccessTimeSetName, lruItem);" +
+                            "                local removedChannelName = KEYS[6];" +
+                            "                local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" +
+                            "                redis.call('publish', removedChannelName, msg);" +
+                            "            end;" +
+                            "        end" +
+                            "    end;" +
+                            "end;"
+
+                            // value
+                            + "local val = struct.pack('dLc0', tonumber(ARGV[4]), string.len(ARGV[6]), ARGV[6]); "
+                            + "redis.call('hset', KEYS[1], ARGV[5], val); "
+
+                            + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); "
+                            + "redis.call('publish', KEYS[4], msg); "
+
+                            + "return nil;"
+                        + "else "
+                            + "local t, val = struct.unpack('dLc0', value); "
+                            + "redis.call('zadd', KEYS[3], t + ARGV[1], ARGV[5]); "
+                            + "return val;"
+                        + "end; ",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
+                        getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)),
+                System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize);
         if (hasNoWriter()) {
             return future;
         }
-        
+
         MapWriterTask<V> listener = new MapWriterTask<V>() {
             @Override
             protected void execute() {
                 options.getWriter().write(key, value);
             }
-            
+
             @Override
             protected boolean condition(Future<V> future) {
                 return future.getNow() == null;
@@ -335,72 +388,81 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     @Override
     protected RFuture<Boolean> removeOperationAsync(Object key, Object value) {
         return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
-                    "local value = redis.call('hget', KEYS[1], ARGV[2]); "
-                  + "if value == false then "
-                      + "return 0; "
-                  + "end; "
-                  + "local t, val = struct.unpack('dLc0', value); "
-                  + "local expireDate = 92233720368547758; " +
-                    "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-                  + "if expireDateScore ~= false then "
-                      + "expireDate = tonumber(expireDateScore) "
-                  + "end; "
-                  + "if t ~= 0 then "
-                      + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                      + "if expireIdle ~= false then "
-                          + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                      + "end; "
-                  + "end; "
-                  + "if expireDate <= tonumber(ARGV[1]) then "
-                      + "return 0; "
-                  + "end; "
-              
-                + "if val == ARGV[3] then "
-                    + "redis.call('zrem', KEYS[2], ARGV[2]); "
-                    + "redis.call('zrem', KEYS[3], ARGV[2]); "
-                    + "redis.call('hdel', KEYS[1], ARGV[2]); "
-                    + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(val), val); "
-                    + "redis.call('publish', KEYS[4], msg); "
-                    + "return 1; "
-                + "else "
-                    + "return 0; "
-                + "end",
-                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key)), 
-                System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
+                "local value = redis.call('hget', KEYS[1], ARGV[2]); "
+                        + "if value == false then "
+                            + "return 0; "
+                        + "end; "
+                        + "local t, val = struct.unpack('dLc0', value); "
+                        + "local expireDate = 92233720368547758; " +
+                        "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
+                        + "if expireDateScore ~= false then "
+                            + "expireDate = tonumber(expireDateScore) "
+                        + "end; "
+                        + "if t ~= 0 then "
+                            + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
+                            + "if expireIdle ~= false then "
+                                + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                            + "end; "
+                        + "end; "
+                        + "if expireDate <= tonumber(ARGV[1]) then "
+                            + "return 0; "
+                        + "end; "
+
+                        + "if val == ARGV[3] then "
+                            + "redis.call('zrem', KEYS[2], ARGV[2]); "
+                            + "redis.call('zrem', KEYS[3], ARGV[2]); "
+                            + "local maxSize = tonumber(ARGV[4]);" +
+                                "if maxSize ~= 0 then" +
+                                "   redis.call('zrem', KEYS[5], ARGV[2]);" +
+                                "end;"
+                            + "redis.call('hdel', KEYS[1], ARGV[2]); "
+                            + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(val), val); "
+                            + "redis.call('publish', KEYS[4], msg); "
+                            + "return 1; "
+                        + "else "
+                            + "return 0; "
+                        + "end",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key),
+                        getLastAccessTimeSetNameByKey(key)),
+                System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize);
     }
 
     @Override
     protected RFuture<V> getOperationAsync(K key) {
         checkKey(key);
-        
+
         return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
-                   "local value = redis.call('hget', KEYS[1], ARGV[2]); "
-                 + "if value == false then "
-                     + "return nil; "
-                 + "end; "
-                 + "local t, val = struct.unpack('dLc0', value); "
-                 + "local expireDate = 92233720368547758; " +
-                   "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-                 + "if expireDateScore ~= false then "
-                     + "expireDate = tonumber(expireDateScore) "
-                 + "end; "
-                 + "if t ~= 0 then "
-                     + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                     + "if expireIdle ~= false then "
-                         + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
-                             + "local value = struct.pack('dLc0', t, string.len(val), val); "
-                             + "redis.call('hset', KEYS[1], ARGV[2], value); "
-                             + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); "
-                         + "end; "
-                         + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                     + "end; "
-                 + "end; "
-                 + "if expireDate <= tonumber(ARGV[1]) then "
-                     + "return nil; "
-                 + "end; "
-                 + "return val; ",
-                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key)), 
-                System.currentTimeMillis(), encodeMapKey(key));
+                "local value = redis.call('hget', KEYS[1], ARGV[2]); "
+                        + "if value == false then "
+                            + "return nil; "
+                        + "end; "
+                        + "local t, val = struct.unpack('dLc0', value); "
+                        + "local expireDate = 92233720368547758; " +
+                        "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
+                        + "if expireDateScore ~= false then "
+                            + "expireDate = tonumber(expireDateScore) "
+                        + "end; "
+                        + "if t ~= 0 then "
+                            + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
+                            + "if expireIdle ~= false then "
+                                + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
+                                    + "local value = struct.pack('dLc0', t, string.len(val), val); "
+                                    + "redis.call('hset', KEYS[1], ARGV[2], value); "
+                                    + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); "
+                                + "end; "
+                                + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                            + "end; "
+                        + "end; "
+                        + "if expireDate <= tonumber(ARGV[1]) then "
+                            + "return nil; "
+                        + "end; "
+                        + "local maxSize = tonumber(ARGV[3]);" +
+                        "if maxSize ~= 0 then" +
+                        "   redis.call('zadd', KEYS[4], tonumber(ARGV[1]), ARGV[2]);" +
+                        "end;"
+                        + "return val; ",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getLastAccessTimeSetNameByKey(key)),
+                System.currentTimeMillis(), encodeMapKey(key), maxSize);
     }
 
     @Override
@@ -411,121 +473,203 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     @Override
     protected RFuture<V> putOperationAsync(K key, V value) {
         return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
-                  "local v = redis.call('hget', KEYS[1], ARGV[2]); " + 
-                  "local exists = false;"
-                + "if v ~= false then "
-                  + "local t, val = struct.unpack('dLc0', v); "
-                  + "local expireDate = 92233720368547758; "
-                  + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-                  + "if expireDateScore ~= false then "
-                      + "expireDate = tonumber(expireDateScore) "
-                  + "end; "
-                  + "if t ~= 0 then "
-                      + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                      + "if expireIdle ~= false then "
-                          + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                      + "end; "
-                  + "end; "
-                  + "if expireDate > tonumber(ARGV[1]) then "
-                      + "exists = true; "
-                  + "end; "           
-              + "end; "
-                
-                + "local value = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); "
-                + "redis.call('hset', KEYS[1], ARGV[2], value); "
-                + "if exists == false then "
-                    + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
-                    + "redis.call('publish', KEYS[4], msg); "
-                    + "return nil; "
-                + "end; "
-                    
-                + "local t, val = struct.unpack('dLc0', v); "
-                + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val); "
-                + "redis.call('publish', KEYS[5], msg); "
-                + "return val; ",
-                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)), 
-                System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
+        "local v = redis.call('hget', KEYS[1], ARGV[2]);" +
+                "local exists = false;" +
+                "if v ~= false then" +
+                "    local t, val = struct.unpack('dLc0', v);" +
+                "    local expireDate = 92233720368547758;" +
+                "    local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]);" +
+                "    if expireDateScore ~= false then" +
+                "        expireDate = tonumber(expireDateScore)" +
+                "    end;" +
+                "    if t ~= 0 then" +
+                "        local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]);" +
+                "        if expireIdle ~= false then" +
+                "            expireDate = math.min(expireDate, tonumber(expireIdle))" +
+                "        end;" +
+                "    end;" +
+                "    if expireDate > tonumber(ARGV[1]) then" +
+                "        exists = true;" +
+                "    end;" +
+                "end;" +
+                "" +
+                "local value = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]);" +
+                "redis.call('hset', KEYS[1], ARGV[2], value);" +
+                "local currentTime = tonumber(ARGV[1]);" +
+                "local lastAccessTimeSetName = KEYS[6];" +
+                "local maxSize = tonumber(ARGV[4]);" +
+                "if exists == false then" +
+                "    if maxSize ~= 0 then" +
+                "        redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" +
+                "        local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" +
+                "        if cacheSize >= maxSize then" +
+                "            local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" +
+                "            for index, lruItem in ipairs(lruItems) do" +
+                "                if lruItem then" +
+                "                    local lruItemValue = redis.call('hget', KEYS[1], lruItem);" +
+                "                    redis.call('hdel', KEYS[1], lruItem);" +
+                "                    redis.call('zrem', KEYS[2], lruItem);" +
+                "                    redis.call('zrem', KEYS[3], lruItem);" +
+                "                    redis.call('zrem', lastAccessTimeSetName, lruItem);" +
+                "                    local removedChannelName = KEYS[7];" +
+                "                    local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" +
+                "                    redis.call('publish', removedChannelName, msg);" +
+                "                end;" +
+                "            end" +
+                "        end;" +
+                "    end;" +
+                "    local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]);" +
+                "    redis.call('publish', KEYS[4], msg);" +
+                "    return nil;" +
+                "else" +
+                "    if maxSize ~= 0 then" +
+                "        redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" +
+                "    end;" +
+                "end;" +
+                "" +
+                "local t, val = struct.unpack('dLc0', v);" +
+                "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val);" +
+                "redis.call('publish', KEYS[5], msg);" +
+                "return val;",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
+                        getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)),
+                System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize);
     }
 
     @Override
     protected RFuture<V> putIfAbsentOperationAsync(K key, V value) {
         return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
                 "local value = redis.call('hget', KEYS[1], ARGV[2]); "
-              + "if value ~= false then "
-                  + "local t, val = struct.unpack('dLc0', value); "
-                  + "local expireDate = 92233720368547758; "
-                  + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-                  + "if expireDateScore ~= false then "
-                      + "expireDate = tonumber(expireDateScore) "
-                  + "end; "
-                  + "if t ~= 0 then "
-                      + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                      + "if expireIdle ~= false then "
-                          + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                      + "end; "
-                  + "end; "
-                  + "if expireDate > tonumber(ARGV[1]) then "
-                      + "return val; "
-                  + "end; "           
-              + "end; "
-                
-                 + "local value = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); "
-                 + "redis.call('hset', KEYS[1], ARGV[2], value); "
-                 + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
-                 + "redis.call('publish', KEYS[4], msg); "
-                 + "return nil;",
-                 Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key)), 
-                 System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
+                        + "local maxSize = tonumber(ARGV[4]);"
+                        + "local lastAccessTimeSetName = KEYS[5];"
+                        + "local currentTime = tonumber(ARGV[1]);"
+                        + "if value ~= false then "
+                            + "local t, val = struct.unpack('dLc0', value); "
+                            + "local expireDate = 92233720368547758; "
+                            + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
+                            + "if expireDateScore ~= false then "
+                                + "expireDate = tonumber(expireDateScore) "
+                            + "end; "
+                            + "if t ~= 0 then "
+                                + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
+                                + "if expireIdle ~= false then "
+                                    + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                                + "end; "
+                            + "end; "
+                            + "if expireDate > tonumber(ARGV[1]) then "
+                                + "if maxSize ~= 0 then"
+                                + "    redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);"
+                                + "end;"
+                                + "return val; "
+                            + "end; "
+                        + "end; "
+
+                        + "local value = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); "
+                        + "redis.call('hset', KEYS[1], ARGV[2], value); "
+
+                        // last access time
+                        + "if maxSize ~= 0 then" +
+                        "    redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" +
+                        "    local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" +
+                        "    if cacheSize >= maxSize then" +
+                        "        local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" +
+                        "        for index, lruItem in ipairs(lruItems) do" +
+                        "            if lruItem then" +
+                        "                local lruItemValue = redis.call('hget', KEYS[1], lruItem);" +
+                        "                redis.call('hdel', KEYS[1], lruItem);" +
+                        "                redis.call('zrem', KEYS[2], lruItem);" +
+                        "                redis.call('zrem', KEYS[3], lruItem);" +
+                        "                redis.call('zrem', lastAccessTimeSetName, lruItem);" +
+                        "                local removedChannelName = KEYS[6];" +
+                        "                local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" +
+                        "                redis.call('publish', removedChannelName, msg);" +
+                        "            end;" +
+                        "        end" +
+                        "    end;" +
+                        "end;"
+
+                        + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
+                        + "redis.call('publish', KEYS[4], msg); "
+                        + "return nil;",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
+                        getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)),
+                System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize);
     }
 
     @Override
     public V addAndGet(K key, Number value) {
         return get(addAndGetAsync(key, value));
     }
-    
+
     @Override
     public RFuture<V> addAndGetOperationAsync(K key, Number value) {
         ByteBuf keyState = encodeMapKey(key);
         return commandExecutor.evalWriteAsync(getName(key), StringCodec.INSTANCE,
                 new RedisCommand<Object>("EVAL", new NumberConvertor(value.getClass())),
-                  "local value = redis.call('hget', KEYS[1], ARGV[2]); "
-                 + "local expireDate = 92233720368547758; "
-                 + "local t = 0; "
-                 + "local val = 0; "
-                 + "if value ~= false then "
-                     + "t, val = struct.unpack('dLc0', value); "
-                     + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-                     + "if expireDateScore ~= false then "
-                         + "expireDate = tonumber(expireDateScore) "
-                     + "end; "
-                     + "if t ~= 0 then "
-                         + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                         + "if expireIdle ~= false then "
-                             + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
-                                 + "local value = struct.pack('dLc0', t, string.len(val), val); "
-                                 + "redis.call('hset', KEYS[1], ARGV[2], value); "
-                                 + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); "
-                             + "end; "
-                             + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                         + "end; "
-                     + "end; "
-                 + "end; "
-                     
-                 + "local newValue = tonumber(ARGV[3]); "
-                 + "if value ~= false and expireDate > tonumber(ARGV[1]) then "
-                     + "newValue = tonumber(val) + newValue; "
-                 
-                     + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(newValue), newValue, string.len(val), val); "
-                     + "redis.call('publish', KEYS[5], msg); "
-                 + "else "
-                     + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
-                     + "redis.call('publish', KEYS[4], msg); "
-                 + "end; "
-                 + "local newValuePack = struct.pack('dLc0', t + tonumber(ARGV[1]), string.len(newValue), newValue); "
-                 + "redis.call('hset', KEYS[1], ARGV[2], newValuePack); "
-                 + "return tostring(newValue); ",
-                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)), 
-                System.currentTimeMillis(), keyState, new BigDecimal(value.toString()).toPlainString());
+                "local value = redis.call('hget', KEYS[1], ARGV[2]); "
+                        + "local expireDate = 92233720368547758; "
+                        + "local t = 0; "
+                        + "local val = 0; "
+                        + "if value ~= false then "
+                            + "t, val = struct.unpack('dLc0', value); "
+                            + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
+                            + "if expireDateScore ~= false then "
+                                + "expireDate = tonumber(expireDateScore) "
+                            + "end; "
+                            + "if t ~= 0 then "
+                                + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
+                                + "if expireIdle ~= false then "
+                                    + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
+                                        + "local value = struct.pack('dLc0', t, string.len(val), val); "
+                                        + "redis.call('hset', KEYS[1], ARGV[2], value); "
+                                        + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); "
+                                    + "end; "
+                                    + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                                + "end; "
+                            + "end; "
+                        + "end; "
+
+                        + "local newValue = tonumber(ARGV[3]); "
+                        + "if value ~= false and expireDate > tonumber(ARGV[1]) then "
+                            + "newValue = tonumber(val) + newValue; "
+
+                            + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(newValue), newValue, string.len(val), val); "
+                            + "redis.call('publish', KEYS[5], msg); "
+                        + "else "
+                            + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
+                            + "redis.call('publish', KEYS[4], msg); "
+                        + "end; "
+                        + "local newValuePack = struct.pack('dLc0', t + tonumber(ARGV[1]), string.len(newValue), newValue); "
+                        + "redis.call('hset', KEYS[1], ARGV[2], newValuePack); "
+
+                        // last access time
+                        + "local maxSize = tonumber(ARGV[4]);" +
+                        "if maxSize ~= 0 then" +
+                        "    local currentTime = tonumber(ARGV[1]);" +
+                        "    local lastAccessTimeSetName = KEYS[6];" +
+                        "    redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" +
+                        "    local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" +
+                        "    if cacheSize >= maxSize then" +
+                        "        local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" +
+                        "        for index, lruItem in ipairs(lruItems) do" +
+                        "            if lruItem then" +
+                        "                local lruItemValue = redis.call('hget', KEYS[1], lruItem);" +
+                        "                redis.call('hdel', KEYS[1], lruItem);" +
+                        "                redis.call('zrem', KEYS[2], lruItem);" +
+                        "                redis.call('zrem', KEYS[3], lruItem);" +
+                        "                redis.call('zrem', lastAccessTimeSetName, lruItem);" +
+                        "                local removedChannelName = KEYS[7];" +
+                        "                local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" +
+                        "                redis.call('publish', removedChannelName, msg);" +
+                        "            end;" +
+                        "        end" +
+                        "    end;" +
+                        "end;"
+
+                        + "return tostring(newValue); ",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
+                        getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)),
+                System.currentTimeMillis(), keyState, new BigDecimal(value.toString()).toPlainString(), maxSize);
     }
 
     @Override
@@ -547,7 +691,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     public RFuture<Boolean> fastPutAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
         checkKey(key);
         checkValue(value);
-        
+
         if (ttl < 0) {
             throw new IllegalArgumentException("ttl can't be negative");
         }
@@ -567,11 +711,11 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
         }
 
         RFuture<Boolean> future = fastPutOperationAsync(key, value, ttl, ttlUnit, maxIdleTime, maxIdleUnit);
-        
+
         if (hasNoWriter()) {
             return future;
         }
-        
+
         MapWriterTask<Boolean> listener = new MapWriterTask<Boolean>() {
             @Override
             protected void execute() {
@@ -597,51 +741,77 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
 
         RFuture<Boolean> future = commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
                 "local insertable = false; "
-              + "local value = redis.call('hget', KEYS[1], ARGV[5]); "
-              + "local t, val;"
-              + "if value == false then "
-                  + "insertable = true; "
-                + "else "
-                  + "t, val = struct.unpack('dLc0', value); "
-                  + "local expireDate = 92233720368547758; "
-                  + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); "
-                  + "if expireDateScore ~= false then "
-                      + "expireDate = tonumber(expireDateScore) "
-                + "end; "
-                  + "if t ~= 0 then "
-                      + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); "
-                      + "if expireIdle ~= false then "
-                          + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                      + "end; "
-                  + "end; "
-                  + "if expireDate <= tonumber(ARGV[1]) then "
-                      + "insertable = true; "
-                  + "end; "           
-              + "end; " +
-                
-                  "if tonumber(ARGV[2]) > 0 then "
-                    + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); "
-                + "else "
-                    + "redis.call('zrem', KEYS[2], ARGV[5]); "
-                + "end; "
-                + "if tonumber(ARGV[3]) > 0 then "
-                    + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); "
-                + "else "
-                    + "redis.call('zrem', KEYS[3], ARGV[5]); "
-                + "end; "
-                + "local value = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); " 
-                + "redis.call('hset', KEYS[1], ARGV[5], value); "
-                + "if insertable == true then "
-                    + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); "
-                    + "redis.call('publish', KEYS[4], msg); "
-                    + "return 1;"
-                + "else "
-                    + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6], string.len(val), val); "
-                    + "redis.call('publish', KEYS[5], msg); "
-                    + "return 0;"
-                + "end;",
-                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)), 
-                System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
+                        + "local value = redis.call('hget', KEYS[1], ARGV[5]); "
+                        + "local t, val;"
+                        + "if value == false then "
+                            + "insertable = true; "
+                        + "else "
+                            + "t, val = struct.unpack('dLc0', value); "
+                            + "local expireDate = 92233720368547758; "
+                            + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); "
+                            + "if expireDateScore ~= false then "
+                                + "expireDate = tonumber(expireDateScore) "
+                            + "end; "
+                            + "if t ~= 0 then "
+                                + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); "
+                                + "if expireIdle ~= false then "
+                                    + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                                + "end; "
+                            + "end; "
+                            + "if expireDate <= tonumber(ARGV[1]) then "
+                                + "insertable = true; "
+                            + "end; "
+                        + "end; " +
+
+                        "if tonumber(ARGV[2]) > 0 then "
+                            + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); "
+                        + "else "
+                            + "redis.call('zrem', KEYS[2], ARGV[5]); "
+                        + "end; "
+                        + "if tonumber(ARGV[3]) > 0 then "
+                            + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); "
+                        + "else "
+                            + "redis.call('zrem', KEYS[3], ARGV[5]); "
+                        + "end; " +
+
+                        // last access time
+                        "local maxSize = tonumber(ARGV[7]);" +
+                        "if maxSize ~= 0 then" +
+                        "    local currentTime = tonumber(ARGV[1]);" +
+                        "    local lastAccessTimeSetName = KEYS[6];" +
+                        "    redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]);" +
+                        "    local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" +
+                        "    if cacheSize >= maxSize then" +
+                        "        local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" +
+                        "        for index, lruItem in ipairs(lruItems) do" +
+                        "            if lruItem then" +
+                        "                local lruItemValue = redis.call('hget', KEYS[1], lruItem);" +
+                        "                redis.call('hdel', KEYS[1], lruItem);" +
+                        "                redis.call('zrem', KEYS[2], lruItem);" +
+                        "                redis.call('zrem', KEYS[3], lruItem);" +
+                        "                redis.call('zrem', lastAccessTimeSetName, lruItem);" +
+                        "                local removedChannelName = KEYS[7];" +
+                        "                local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" +
+                        "                redis.call('publish', removedChannelName, msg);" +
+                        "            end;" +
+                        "        end" +
+                        "    end;" +
+                        "end;"
+
+                        + "local value = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); "
+                        + "redis.call('hset', KEYS[1], ARGV[5], value); "
+                        + "if insertable == true then "
+                            + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); "
+                            + "redis.call('publish', KEYS[4], msg); "
+                            + "return 1;"
+                        + "else "
+                            + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6], string.len(val), val); "
+                            + "redis.call('publish', KEYS[5], msg); "
+                            + "return 0;"
+                        + "end;",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
+                        getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)),
+                System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize);
         return future;
     }
 
@@ -659,7 +829,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     public RFuture<V> putAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
         checkKey(key);
         checkValue(value);
-        
+
         if (ttl < 0) {
             throw new IllegalArgumentException("ttl can't be negative");
         }
@@ -694,7 +864,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
         if (hasNoWriter()) {
             return future;
         }
-        
+
         MapWriterTask<V> listener = new MapWriterTask<V>() {
             @Override
             protected void execute() {
@@ -708,66 +878,91 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
             long maxIdleDelta) {
         RFuture<V> future = commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
                 "local insertable = false; "
-              + "local v = redis.call('hget', KEYS[1], ARGV[5]); "
-              + "if v == false then "
-                  + "insertable = true; "
-                + "else "
-                  + "local t, val = struct.unpack('dLc0', v); "
-                  + "local expireDate = 92233720368547758; "
-                  + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); "
-                  + "if expireDateScore ~= false then "
-                      + "expireDate = tonumber(expireDateScore) "
-                + "end; "
-                  + "if t ~= 0 then "
-                      + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); "
-                      + "if expireIdle ~= false then "
-                          + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                      + "end; "
-                  + "end; "
-                  + "if expireDate <= tonumber(ARGV[1]) then "
-                      + "insertable = true; "
-                  + "end; "           
-              + "end; "
-                
-                + "if tonumber(ARGV[2]) > 0 then "
-                    + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); "
-                + "else "
-                    + "redis.call('zrem', KEYS[2], ARGV[5]); "
-                + "end; "
-                + "if tonumber(ARGV[3]) > 0 then "
-                    + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); "
-                + "else "
-                    + "redis.call('zrem', KEYS[3], ARGV[5]); "
-                + "end; "
-                    
-                + "local value = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); "
-                + "redis.call('hset', KEYS[1], ARGV[5], value); "
-                
-                + "if insertable == true then "
-                    + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); "
-                    + "redis.call('publish', KEYS[4], msg); "
-                    + "return nil;"
-                + "end; "
-                    
-                + "local t, val = struct.unpack('dLc0', v); "
-
-                + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6], string.len(val), val); "
-                + "redis.call('publish', KEYS[5], msg); "
-                
-                + "return val",
-                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)), 
-                System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
+                        + "local v = redis.call('hget', KEYS[1], ARGV[5]); "
+                        + "if v == false then "
+                            + "insertable = true; "
+                        + "else "
+                            + "local t, val = struct.unpack('dLc0', v); "
+                            + "local expireDate = 92233720368547758; "
+                            + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); "
+                            + "if expireDateScore ~= false then "
+                                + "expireDate = tonumber(expireDateScore) "
+                            + "end; "
+                            + "if t ~= 0 then "
+                                + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); "
+                                + "if expireIdle ~= false then "
+                                    + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                                + "end; "
+                            + "end; "
+                            + "if expireDate <= tonumber(ARGV[1]) then "
+                                + "insertable = true; "
+                            + "end; "
+                        + "end; "
+
+                        + "if tonumber(ARGV[2]) > 0 then "
+                            + "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); "
+                        + "else "
+                            + "redis.call('zrem', KEYS[2], ARGV[5]); "
+                        + "end; "
+                        + "if tonumber(ARGV[3]) > 0 then "
+                            + "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); "
+                        + "else "
+                            + "redis.call('zrem', KEYS[3], ARGV[5]); "
+                        + "end; "
+
+                        // last access time
+                        + "local maxSize = tonumber(ARGV[7]);" +
+                        "if maxSize ~= 0 then" +
+                        "    local currentTime = tonumber(ARGV[1]);" +
+                        "    local lastAccessTimeSetName = KEYS[6];" +
+                        "    redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]);" +
+                        "    local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" +
+                        "    if cacheSize >= maxSize then" +
+                        "        local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" +
+                        "        for index, lruItem in ipairs(lruItems) do" +
+                        "            if lruItem then" +
+                        "                local lruItemValue = redis.call('hget', KEYS[1], lruItem);" +
+                        "                redis.call('hdel', KEYS[1], lruItem);" +
+                        "                redis.call('zrem', KEYS[2], lruItem);" +
+                        "                redis.call('zrem', KEYS[3], lruItem);" +
+                        "                redis.call('zrem', lastAccessTimeSetName, lruItem);" +
+                        "                local removedChannelName = KEYS[7];" +
+                        "                local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" +
+                        "                redis.call('publish', removedChannelName, msg);" +
+                        "            end;" +
+                        "        end" +
+                        "    end;" +
+                        "end;"
+
+                        + "local value = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); "
+                        + "redis.call('hset', KEYS[1], ARGV[5], value); "
+
+                        + "if insertable == true then "
+                            + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); "
+                            + "redis.call('publish', KEYS[4], msg); "
+                            + "return nil;"
+                        + "end; "
+
+                        + "local t, val = struct.unpack('dLc0', v); "
+
+                        + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6], string.len(val), val); "
+                        + "redis.call('publish', KEYS[5], msg); "
+
+                        + "return val",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
+                        getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)),
+                System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize);
         return future;
     }
 
     String getTimeoutSetNameByKey(Object key) {
         return prefixName("redisson__timeout__set", getName(key));
     }
-    
+
     String getTimeoutSetName(String name) {
         return prefixName("redisson__timeout__set", name);
     }
-    
+
     String getTimeoutSetName() {
         return prefixName("redisson__timeout__set", getName());
     }
@@ -775,11 +970,11 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     String getIdleSetNameByKey(Object key) {
         return prefixName("redisson__idle__set", getName(key));
     }
-    
+
     String getIdleSetName(String name) {
         return prefixName("redisson__idle__set", name);
     }
-    
+
     String getIdleSetName() {
         return prefixName("redisson__idle__set", getName());
     }
@@ -787,7 +982,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     String getCreatedChannelNameByKey(Object key) {
         return prefixName("redisson_map_cache_created", getName(key));
     }
-    
+
     String getCreatedChannelName(String name) {
         return prefixName("redisson_map_cache_created", name);
     }
@@ -837,45 +1032,55 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     public RFuture<V> removeOperationAsync(K key) {
         return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
                 "local value = redis.call('hget', KEYS[1], ARGV[2]); "
-              + "if value == false then "
-                  + "return nil; "
-              + "end; "
-
-              + "local t, val = struct.unpack('dLc0', value); "
-              + "local expireDate = 92233720368547758; " +
-                "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-              + "if expireDateScore ~= false then "
-                  + "expireDate = tonumber(expireDateScore) "
-              + "end; "
-              + "if t ~= 0 then "
-                  + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                  + "if expireIdle ~= false then "
-                     + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                  + "end; "
-              + "end; "
-              + "if expireDate <= tonumber(ARGV[1]) then "
-                  + "return nil; "
-              + "end; "
-
-              + "redis.call('zrem', KEYS[2], ARGV[2]); "
-              + "redis.call('zrem', KEYS[3], ARGV[2]); "
-              + "redis.call('hdel', KEYS[1], ARGV[2]); "
-                  
-                + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(val), val); "
-                + "redis.call('publish', KEYS[4], msg); "
-                + "return val; ",
-                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key)), 
-                System.currentTimeMillis(), encodeMapKey(key));
+                        + "if value == false then "
+                            + "return nil; "
+                        + "end; "
+
+                        + "local t, val = struct.unpack('dLc0', value); "
+                        + "local expireDate = 92233720368547758; " +
+                        "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
+                        + "if expireDateScore ~= false then "
+                            + "expireDate = tonumber(expireDateScore) "
+                        + "end; "
+                        + "if t ~= 0 then "
+                            + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
+                            + "if expireIdle ~= false then "
+                                + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                            + "end; "
+                        + "end; "
+                        + "if expireDate <= tonumber(ARGV[1]) then "
+                            + "return nil; "
+                        + "end; "
+
+                        + "redis.call('zrem', KEYS[2], ARGV[2]); "
+                        + "redis.call('zrem', KEYS[3], ARGV[2]); "
+                        + "local maxSize = tonumber(ARGV[3])"
+                        + "if maxSize ~= 0 then"
+                        + "    redis.call('zrem', KEYS[5], ARGV[2]); "
+                        + "end;"
+                        + "redis.call('hdel', KEYS[1], ARGV[2]); "
+
+                        + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(val), val); "
+                        + "redis.call('publish', KEYS[4], msg); "
+                        + "return val; ",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getRemovedChannelNameByKey(key),
+                        getLastAccessTimeSetNameByKey(key)),
+                System.currentTimeMillis(), encodeMapKey(key), maxSize);
     }
 
     @Override
     protected RFuture<List<Long>> fastRemoveOperationBatchAsync(K... keys) {
-        List<Object> args = new ArrayList<Object>(keys.length);
+        List<Object> args = new ArrayList<Object>(keys.length + 1);
+        args.add(maxSize);
         for (K key : keys) {
             args.add(encodeMapKey(key));
         }
 
         RFuture<List<Long>> future = commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_LIST,
+                "local maxSize = tonumber(table.remove(ARGV, 1));"
+                        + "if maxSize ~= 0 then"
+                        + "    redis.call('zrem', KEYS[5], unpack(ARGV));"
+                        + "end;" +
                         "redis.call('zrem', KEYS[3], unpack(ARGV)); " +
                         "redis.call('zrem', KEYS[2], unpack(ARGV)); " +
                         "for i, key in ipairs(ARGV) do "
@@ -884,40 +1089,45 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                             + "local t, val = struct.unpack('dLc0', v); "
                             + "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(val), val); "
                             + "redis.call('publish', KEYS[4], msg); "
-                        + "end;" + 
+                        + "end;" +
                         "end;" +
-                
-                        "local result = {}; " + 
-                        "for i = 1, #ARGV, 1 do " 
-                        + "local val = redis.call('hdel', KEYS[1], ARGV[i]); "
-                        + "table.insert(result, val); "
-                      + "end;"
-                      + "return result;",
-                        Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName()), 
-                        args.toArray());
+
+                        "local result = {}; " +
+                        "for i = 1, #ARGV, 1 do "
+                            + "local val = redis.call('hdel', KEYS[1], ARGV[i]); "
+                            + "table.insert(result, val); "
+                        + "end;"
+                        + "return result;",
+                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName(), getLastAccessTimeSetName()),
+                args.toArray());
         return future;
     }
-    
+
     @Override
     protected RFuture<Long> fastRemoveOperationAsync(K ... keys) {
-        List<Object> params = new ArrayList<Object>(keys.length);
+        List<Object> params = new ArrayList<Object>(keys.length + 1);
+        params.add(maxSize);
         for (K key : keys) {
             params.add(encodeMapKey(key));
         }
-        
+
         return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG,
-                "redis.call('zrem', KEYS[3], unpack(ARGV)); " +
-                "redis.call('zrem', KEYS[2], unpack(ARGV)); " +
-                "for i, key in ipairs(ARGV) do "
-                + "local v = redis.call('hget', KEYS[1], key); "
-                + "if v ~= false then "
-                    + "local t, val = struct.unpack('dLc0', v); "
-                    + "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(val), val); "
-                    + "redis.call('publish', KEYS[4], msg); "
-                + "end;" + 
-                "end;" +
-                "return redis.call('hdel', KEYS[1], unpack(ARGV)); ",
-                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName()), 
+                "local maxSize = tonumber(table.remove(ARGV, 1));"
+                        + "if maxSize ~= 0 then"
+                        + "    redis.call('zrem', KEYS[5], unpack(ARGV));"
+                        + "end;" +
+                        "redis.call('zrem', KEYS[3], unpack(ARGV)); " +
+                        "redis.call('zrem', KEYS[2], unpack(ARGV)); " +
+                        "for i, key in ipairs(ARGV) do "
+                        + "local v = redis.call('hget', KEYS[1], key); "
+                        + "if v ~= false then "
+                            + "local t, val = struct.unpack('dLc0', v); "
+                            + "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(val), val); "
+                            + "redis.call('publish', KEYS[4], msg); "
+                        + "end;" +
+                        "end;" +
+                        "return redis.call('hdel', KEYS[1], unpack(ARGV)); ",
+                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getRemovedChannelName(), getLastAccessTimeSetName()),
                 params.toArray());
     }
 
@@ -925,7 +1135,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     MapScanResult<ScanObjectEntry, ScanObjectEntry> scanIterator(String name, InetSocketAddress client, long startPos, String pattern) {
         return get(scanIteratorAsync(name, client, startPos, pattern));
     }
-    
+
     public RFuture<MapScanResult<ScanObjectEntry, ScanObjectEntry>> scanIteratorAsync(final String name, InetSocketAddress client, long startPos, String pattern) {
         List<Object> params = new ArrayList<Object>();
         params.add(System.currentTimeMillis());
@@ -933,8 +1143,8 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
         if (pattern != null) {
             params.add(pattern);
         }
-        
-        RedisCommand<MapCacheScanResult<Object, Object>> EVAL_HSCAN = new RedisCommand<MapCacheScanResult<Object, Object>>("EVAL", 
+
+        RedisCommand<MapCacheScanResult<Object, Object>> EVAL_HSCAN = new RedisCommand<MapCacheScanResult<Object, Object>>("EVAL",
                 new ListMultiDecoder(new LongMultiDecoder(), new ObjectMapDecoder(new MapScanCodec(codec)), new ObjectListDecoder(codec), new MapCacheScanResultReplayDecoder()), ValueType.MAP);
         RFuture<MapCacheScanResult<ScanObjectEntry, ScanObjectEntry>> f = commandExecutor.evalReadAsync(client, name, codec, EVAL_HSCAN,
                 "local result = {}; "
@@ -972,10 +1182,10 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                         + "end; "
                     + "end; "
                 + "end;"
-                + "return {res[1], result, idleKeys};", 
-                Arrays.<Object>asList(name, getTimeoutSetName(name), getIdleSetName(name)), 
+                + "return {res[1], result, idleKeys};",
+                Arrays.<Object>asList(name, getTimeoutSetName(name), getIdleSetName(name)),
                 params.toArray());
-        
+
         f.addListener(new FutureListener<MapCacheScanResult<ScanObjectEntry, ScanObjectEntry>>() {
             @Override
             public void operationComplete(Future<MapCacheScanResult<ScanObjectEntry, ScanObjectEntry>> future)
@@ -985,7 +1195,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                     if (res.getIdleKeys().isEmpty()) {
                         return;
                     }
-                    
+
                     List<Object> args = new ArrayList<Object>(res.getIdleKeys().size() + 1);
                     args.add(System.currentTimeMillis());
                     args.addAll(res.getIdleKeys());
@@ -998,7 +1208,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                                       + "if value ~= false then "
                                           + "local key = ARGV[i]; "
                                           + "local t, val = struct.unpack('dLc0', value); "
-    
+
                                           + "if t ~= 0 then "
                                               + "local expireIdle = redis.call('zscore', KEYS[2], key); "
                                               + "if expireIdle ~= false then "
@@ -1012,7 +1222,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                                       + "end; "
                                   + "end; ",
                             Arrays.<Object>asList(name, getIdleSetName(name)), args.toArray());
-                    
+
                 }
             }
         });
@@ -1025,103 +1235,159 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     protected RFuture<Boolean> fastPutOperationAsync(K key, V value) {
         return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
                 "local insertable = false; "
-              + "local v = redis.call('hget', KEYS[1], ARGV[2]); "
-              + "if v == false then "
-                  + "insertable = true; "
-              + "else "
-                  + "local t, val = struct.unpack('dLc0', v); "
-                  + "local expireDate = 92233720368547758; "
-                  + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-                  + "if expireDateScore ~= false then "
-                      + "expireDate = tonumber(expireDateScore) "
-                  + "end; "
-                  + "if t ~= 0 then "
-                      + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                      + "if expireIdle ~= false then "
-                          + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                      + "end; "
-                  + "end; "
-                  + "if expireDate <= tonumber(ARGV[1]) then "
-                      + "insertable = true; "
-                  + "end; "           
-              + "end; " +
-                
-                "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); "
-              + "redis.call('hset', KEYS[1], ARGV[2], val); "
-                
-            + "if insertable == true then "
-                + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
-                + "redis.call('publish', KEYS[4], msg); "
-                + "return 1;"
-            + "else "
-                + "local t, val = struct.unpack('dLc0', v); "
-                + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val); "
-                + "redis.call('publish', KEYS[5], msg); "
-                + "return 0;"
-            + "end;",
-          Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key), getUpdatedChannelNameByKey(key)),
-          System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
+                        + "local v = redis.call('hget', KEYS[1], ARGV[2]); "
+                        + "if v == false then "
+                                + "insertable = true; "
+                        + "else "
+                            + "local t, val = struct.unpack('dLc0', v); "
+                            + "local expireDate = 92233720368547758; "
+                            + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
+                            + "if expireDateScore ~= false then "
+                                + "expireDate = tonumber(expireDateScore) "
+                            + "end; "
+                            + "if t ~= 0 then "
+                                + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
+                                + "if expireIdle ~= false then "
+                                    + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                                + "end; "
+                            + "end; "
+                            + "if expireDate <= tonumber(ARGV[1]) then "
+                                + "insertable = true; "
+                            + "end; "
+                        + "end; " +
+
+                        "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); "
+                        + "redis.call('hset', KEYS[1], ARGV[2], val); " +
+
+                        // last access time
+                        "local maxSize = tonumber(ARGV[4]);" +
+                        "if maxSize ~= 0 then" +
+                        "    local currentTime = tonumber(ARGV[1]);" +
+                        "    local lastAccessTimeSetName = KEYS[6];" +
+                        "    redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" +
+                        "    local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" +
+                        "    if cacheSize >= maxSize then" +
+                        "        local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" +
+                        "        for index, lruItem in ipairs(lruItems) do" +
+                        "            if lruItem then" +
+                        "                local lruItemValue = redis.call('hget', KEYS[1], lruItem);" +
+                        "                redis.call('hdel', KEYS[1], lruItem);" +
+                        "                redis.call('zrem', KEYS[2], lruItem);" +
+                        "                redis.call('zrem', KEYS[3], lruItem);" +
+                        "                redis.call('zrem', lastAccessTimeSetName, lruItem);" +
+                        "                local removedChannelName = KEYS[7];" +
+                        "                local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" +
+                        "                redis.call('publish', removedChannelName, msg);" +
+                        "            end;" +
+                        "        end" +
+                        "    end;" +
+                        "end;"
+
+                        + "if insertable == true then "
+                            + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
+                            + "redis.call('publish', KEYS[4], msg); "
+                            + "return 1;"
+                        + "else "
+                            + "local t, val = struct.unpack('dLc0', v); "
+                            + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val); "
+                            + "redis.call('publish', KEYS[5], msg); "
+                            + "return 0;"
+                        + "end;",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
+                        getUpdatedChannelNameByKey(key), getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)),
+                System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize);
     }
 
     @Override
     protected RFuture<Boolean> fastPutIfAbsentOperationAsync(K key, V value) {
         return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
                 "local value = redis.call('hget', KEYS[1], ARGV[2]); "
-              + "if value == false then "
-                  + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); "
-                  + "redis.call('hset', KEYS[1], ARGV[2], val); "
-                  + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
-                  + "redis.call('publish', KEYS[4], msg); "
-                  + "return 1; "
-              + "end; "
-              + "local t, val = struct.unpack('dLc0', value); "
-              + "local expireDate = 92233720368547758; " +
-                "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-              + "if expireDateScore ~= false then "
-                  + "expireDate = tonumber(expireDateScore) "
-              + "end; "
-              + "if t ~= 0 then "
-                  + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                  + "if expireIdle ~= false then "
-                      + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
-                          + "local value = struct.pack('dLc0', t, string.len(val), val); "
-                          + "redis.call('hset', KEYS[1], ARGV[2], value); "
-                          + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); "
-                      + "end; "
-                      + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                  + "end; "
-              + "end; "
-              + "if expireDate > tonumber(ARGV[1]) then "
-                  + "return 0; "
-              + "end; "
-              
-              + "redis.call('zrem', KEYS[2], ARGV[2]); "
-              + "redis.call('zrem', KEYS[3], ARGV[2]); "
-              + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); "
-              + "redis.call('hset', KEYS[1], ARGV[2], val); "
-              
-              + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
-              + "redis.call('publish', KEYS[4], msg); "
-              + "return 1; ",
-             Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key)), 
-             System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
+                        + "local lastAccessTimeSetName = KEYS[5];"
+                        + "local maxSize = tonumber(ARGV[4]);"
+                        + "local currentTime = tonumber(ARGV[1]);"
+                        + "if value == false then "
+                            + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); "
+                            + "redis.call('hset', KEYS[1], ARGV[2], val); "
+                            + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
+                            + "redis.call('publish', KEYS[4], msg); "+
+
+                            // last access time
+
+                            "if maxSize ~= 0 then" +
+                            "    redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);" +
+                            "    local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" +
+                            "    if cacheSize >= maxSize then" +
+                            "        local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" +
+                            "        for index, lruItem in ipairs(lruItems) do" +
+                            "            if lruItem then" +
+                            "                local lruItemValue = redis.call('hget', KEYS[1], lruItem);" +
+                            "                redis.call('hdel', KEYS[1], lruItem);" +
+                            "                redis.call('zrem', KEYS[2], lruItem);" +
+                            "                redis.call('zrem', KEYS[3], lruItem);" +
+                            "                redis.call('zrem', lastAccessTimeSetName, lruItem);" +
+                            "                local removedChannelName = KEYS[6];" +
+                            "                local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" +
+                            "                redis.call('publish', removedChannelName, msg);" +
+                            "            end;" +
+                            "        end" +
+                            "    end;" +
+                            "end;"
+
+                            + "return 1; "
+                        + "end; "
+
+                        + "if maxSize ~= 0 then"
+                        + "    redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[2]);"
+                        + "end;"
+                        + "local t, val = struct.unpack('dLc0', value); "
+                        + "local expireDate = 92233720368547758; "
+                        + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
+                        + "if expireDateScore ~= false then "
+                            + "expireDate = tonumber(expireDateScore) "
+                        + "end; "
+                        + "if t ~= 0 then "
+                            + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
+                            + "if expireIdle ~= false then "
+                                + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
+                                    + "local value = struct.pack('dLc0', t, string.len(val), val); "
+                                    + "redis.call('hset', KEYS[1], ARGV[2], value); "
+                                    + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), ARGV[2]); "
+                                + "end; "
+                                + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                            + "end; "
+                        + "end; "
+                        + "if expireDate > tonumber(ARGV[1]) then "
+                            + "return 0; "
+                        + "end; "
+
+                        + "redis.call('zrem', KEYS[2], ARGV[2]); "
+                        + "redis.call('zrem', KEYS[3], ARGV[2]); "
+                        + "local val = struct.pack('dLc0', 0, string.len(ARGV[3]), ARGV[3]); "
+                        + "redis.call('hset', KEYS[1], ARGV[2], val); "
+
+                        + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3]); "
+                        + "redis.call('publish', KEYS[4], msg); "
+                        + "return 1; ",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
+                        getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)),
+                System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value), maxSize);
     }
-    
+
     @Override
 	public boolean fastPutIfAbsent(K key, V value, long ttl, TimeUnit ttlUnit) {
 		return fastPutIfAbsent(key, value, ttl, ttlUnit, 0, null);
 	}
-    
+
     @Override
     public boolean fastPutIfAbsent(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
     	return get(fastPutIfAbsentAsync(key, value, ttl, ttlUnit, maxIdleTime, maxIdleUnit));
     }
-	
+
     @Override
 	public RFuture<Boolean> fastPutIfAbsentAsync(final K key, final V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
         checkKey(key);
         checkValue(value);
-        
+
 		if (ttl < 0) {
             throw new IllegalArgumentException("ttl can't be negative");
         }
@@ -1153,62 +1419,81 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
         }
 
         RFuture<Boolean> future = commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
-            "local insertable = false; "
-            + "local value = redis.call('hget', KEYS[1], ARGV[5]); "
-            + "if value == false then "
-            	+ "insertable = true; "
-        	+ "else "
-        		+ "if insertable == false then "
-	        		+ "local t, val = struct.unpack('dLc0', value); "
-	                + "local expireDate = 92233720368547758; "
-	                + "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); "
-	                + "if expireDateScore ~= false then "
-	                    + "expireDate = tonumber(expireDateScore) "
-	                + "end; "
-	                + "if t ~= 0 then "
-	                    + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); "
-	                    + "if expireIdle ~= false then "
-	                        + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-	                    + "end; "
-	                + "end; "
-	                + "if expireDate <= tonumber(ARGV[1]) then "
-	                    + "insertable = true; "
-	                + "end; "        	
-        		+ "end; "
-			+ "end; "
-        		
-			+ "if insertable == true then "
-				// ttl
-				+ "if tonumber(ARGV[2]) > 0 then "
-					+ "redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); "
-				+ "else "
-					+ "redis.call('zrem', KEYS[2], ARGV[5]); "
-				+ "end; "
-					
-				// idle
-				+ "if tonumber(ARGV[3]) > 0 then "
-					+ "redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); "
-				+ "else "
-					+ "redis.call('zrem', KEYS[3], ARGV[5]); "
-				+ "end; "
-				
-				// value
-				+ "local val = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]); "
-				+ "redis.call('hset', KEYS[1], ARGV[5], val); "
-				
-                + "local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]); "
-                + "redis.call('publish', KEYS[4], msg); "
-				
-				+ "return 1; "
-			+ "else "
-				+ "return 0; "
-			+ "end; ",
-			Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key)), 
-			System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value));
+                "local insertable = false;" +
+                        "local value = redis.call('hget', KEYS[1], ARGV[5]);" +
+                        "if value == false then" +
+                        "    insertable = true;" +
+                        "else" +
+                        "    if insertable == false then" +
+                        "        local t, val = struct.unpack('dLc0', value);" +
+                        "        local expireDate = 92233720368547758;" +
+                        "        local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]);" +
+                        "        if expireDateScore ~= false then" +
+                        "            expireDate = tonumber(expireDateScore)" +
+                        "        end;" +
+                        "        if t ~= 0 then" +
+                        "            local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]);" +
+                        "            if expireIdle ~= false then" +
+                        "                expireDate = math.min(expireDate, tonumber(expireIdle))" +
+                        "            end;" +
+                        "        end;" +
+                        "        if expireDate <= tonumber(ARGV[1]) then" +
+                        "            insertable = true;" +
+                        "        end;" +
+                        "    end;" +
+                        "end;" +
+                        "if insertable == true then" +
+                             // ttl
+                        "    if tonumber(ARGV[2]) > 0 then" +
+                        "        redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]);" +
+                        "    else" +
+                        "        redis.call('zrem', KEYS[2], ARGV[5]);" +
+                        "    end;" +
+                             // idle
+                        "    if tonumber(ARGV[3]) > 0 then" +
+                        "        redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]);" +
+                        "    else" +
+                        "        redis.call('zrem', KEYS[3], ARGV[5]);" +
+                        "    end;" +
+                             // last access time
+                        "    local maxSize = tonumber(ARGV[7]);" +
+                        "    if maxSize ~= 0 then" +
+                        "        local currentTime = tonumber(ARGV[1]);" +
+                        "        local lastAccessTimeSetName = KEYS[5];" +
+                        "        redis.call('zadd', lastAccessTimeSetName, currentTime, ARGV[5]);" +
+                        "        local cacheSize = tonumber(redis.call('hlen', KEYS[1]));" +
+                        "        if cacheSize >= maxSize then" +
+                        "            local lruItems = redis.call('zrange', lastAccessTimeSetName, 0, cacheSize - maxSize);" +
+                        "            for index, lruItem in ipairs(lruItems) do" +
+                        "                if lruItem then" +
+                        "                    local lruItemValue = redis.call('hget', KEYS[1], lruItem);" +
+                        "                    redis.call('hdel', KEYS[1], lruItem);" +
+                        "                    redis.call('zrem', KEYS[2], lruItem);" +
+                        "                    redis.call('zrem', KEYS[3], lruItem);" +
+                        "                    redis.call('zrem', lastAccessTimeSetName, lruItem);" +
+                        "                    local removedChannelName = KEYS[6];" +
+                        "                    local msg = struct.pack('Lc0Lc0', string.len(lruItem), lruItem, string.len(lruItemValue), lruItemValue);" +
+                        "                    redis.call('publish', removedChannelName, msg);" +
+                        "                end;" +
+                        "            end" +
+                        "        end;" +
+                        "    end;" +
+                             // value
+                        "    local val = struct.pack('dLc0', ARGV[4], string.len(ARGV[6]), ARGV[6]);" +
+                        "    redis.call('hset', KEYS[1], ARGV[5], val); " +
+                        "    local msg = struct.pack('Lc0Lc0', string.len(ARGV[5]), ARGV[5], string.len(ARGV[6]), ARGV[6]);" +
+                        "    redis.call('publish', KEYS[4], msg); " +
+                        "    return 1; " +
+                        "else " +
+                        "    return 0; " +
+                        "end; ",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getCreatedChannelNameByKey(key),
+                        getLastAccessTimeSetNameByKey(key), getRemovedChannelNameByKey(key)),
+                System.currentTimeMillis(), ttlTimeout, maxIdleTimeout, maxIdleDelta, encodeMapKey(key), encodeMapValue(value), maxSize);
         if (hasNoWriter()) {
             return future;
         }
-        
+
         MapWriterTask<Boolean> listener = new MapWriterTask<Boolean>() {
             @Override
             protected void execute() {
@@ -1220,72 +1505,77 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
             }
         };
         return mapWriterFuture(future, listener);
-	}
+    }
+
+    private String getLastAccessTimeSetNameByKey(Object key) {
+        return prefixName("redisson__last_access__set", getName(key));
+    }
+
+    private String getLastAccessTimeSetName() {
+        return prefixName("redisson__last_access__set", getName());
+    }
 
     @Override
     protected RFuture<Boolean> replaceOperationAsync(K key, V oldValue, V newValue) {
         return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_BOOLEAN,
-                  "local v = redis.call('hget', KEYS[1], ARGV[2]); "
-                + "if v == false then "
-                    + "return 0;"
-                + "end;"
-                + "local expireDate = 92233720368547758; " +
-                "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-                + "if expireDateScore ~= false then "
-                    + "expireDate = tonumber(expireDateScore) "
-                + "end; "
-
-                + "local t, val = struct.unpack('dLc0', v); "
-                + "if t ~= 0 then "
-                    + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                    + "if expireIdle ~= false then "
-                        + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                    + "end; "
-                + "end; "
-                + "if expireDate > tonumber(ARGV[1]) and val == ARGV[3] then "
-                    + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[4]), ARGV[4], string.len(ARGV[3]), ARGV[3]); "
-                    + "redis.call('publish', KEYS[4], msg); "
-                
-                    + "local value = struct.pack('dLc0', t, string.len(ARGV[4]), ARGV[4]); "
-                    + "redis.call('hset', KEYS[1], ARGV[2], value); "
-                    + "return 1; "
-                + "end; "
-                + "return 0; ",
-                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getUpdatedChannelNameByKey(key)), 
-                System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(oldValue), encodeMapValue(newValue));
+            "local v = redis.call('hget', KEYS[1], ARGV[2]);" +
+            "if v == false then" +
+            "    return 0;" +
+            "end;" +
+            "local expireDate = 92233720368547758;" +
+            "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]);" +
+            "if expireDateScore ~= false then" +
+            "    expireDate = tonumber(expireDateScore)" +
+            "end;" +
+            "" +
+            "local t, val = struct.unpack('dLc0', v);" +
+            "if t ~= 0 then" +
+            "    local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]);" +
+            "    if expireIdle ~= false then" +
+            "        expireDate = math.min(expireDate, tonumber(expireIdle))" +
+            "    end;" +
+            "end;" +
+            "if expireDate > tonumber(ARGV[1]) and val == ARGV[3] then" +
+            "    local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[4]), ARGV[4], string.len(ARGV[3]), ARGV[3]);" +
+            "    redis.call('publish', KEYS[4], msg);" +
+            "" +
+            "    local value = struct.pack('dLc0', t, string.len(ARGV[4]), ARGV[4]);" +
+            "    redis.call('hset', KEYS[1], ARGV[2], value);" +
+            "    return 1;" +
+            "end;" +
+            "return 0;",
+            Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getUpdatedChannelNameByKey(key)),
+            System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(oldValue), encodeMapValue(newValue));
     }
 
     @Override
     protected RFuture<V> replaceOperationAsync(K key, V value) {
         return commandExecutor.evalWriteAsync(getName(key), codec, RedisCommands.EVAL_MAP_VALUE,
-                    "local value = redis.call('hget', KEYS[1], ARGV[2]); "
-                  + "if value == false then "
-                      + "return nil; "
-                  + "end; "
-                  + "local t, val = struct.unpack('dLc0', value); "
-                  + "local expireDate = 92233720368547758; " +
-                    "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]); "
-                  + "if expireDateScore ~= false then "
-                      + "expireDate = tonumber(expireDateScore) "
-                  + "end; "
-                  + "if t ~= 0 then "
-                      + "local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]); "
-                      + "if expireIdle ~= false then "
-                          + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
-                      + "end; "
-                  + "end; "
-                  + "if expireDate <= tonumber(ARGV[1]) then "
-                      + "return nil; "
-                  + "end; "
-                
-                    + "local value = struct.pack('dLc0', t, string.len(ARGV[3]), ARGV[3]); "
-                    + "redis.call('hset', KEYS[1], ARGV[2], value); "
-                    
-                    + "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val); "
-                    + "redis.call('publish', KEYS[4], msg); "
-                    
-                    + "return val; ",
-                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getUpdatedChannelNameByKey(key)), 
+                "local value = redis.call('hget', KEYS[1], ARGV[2]);" +
+                "if value == false then" +
+                "    return nil;" +
+                "end;" +
+                "local t, val = struct.unpack('dLc0', value);" +
+                "local expireDate = 92233720368547758;" +
+                "local expireDateScore = redis.call('zscore', KEYS[2], ARGV[2]);" +
+                "if expireDateScore ~= false then" +
+                "    expireDate = tonumber(expireDateScore)" +
+                "end;" +
+                "if t ~= 0 then" +
+                "    local expireIdle = redis.call('zscore', KEYS[3], ARGV[2]);" +
+                "    if expireIdle ~= false then" +
+                "        expireDate = math.min(expireDate, tonumber(expireIdle))" +
+                "    end;" +
+                "end;" +
+                "if expireDate <= tonumber(ARGV[1]) then" +
+                "    return nil;" +
+                "end;" +
+                "local value = struct.pack('dLc0', t, string.len(ARGV[3]), ARGV[3]);" +
+                "redis.call('hset', KEYS[1], ARGV[2], value);" +
+                "local msg = struct.pack('Lc0Lc0Lc0', string.len(ARGV[2]), ARGV[2], string.len(ARGV[3]), ARGV[3], string.len(val), val);" +
+                "redis.call('publish', KEYS[4], msg);" +
+                "return val;",
+                Arrays.<Object>asList(getName(key), getTimeoutSetNameByKey(key), getIdleSetNameByKey(key), getUpdatedChannelNameByKey(key)),
                 System.currentTimeMillis(), encodeMapKey(key), encodeMapValue(value));
 
     }
@@ -1300,7 +1590,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
             if (t.getValue() == null) {
                 throw new NullPointerException("map value can't be null");
             }
-            
+
             params.add(encodeMapKey(t.getKey()));
             params.add(encodeMapValue(t.getValue()));
         }
@@ -1311,20 +1601,20 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                         + "local val = struct.pack('dLc0', 0, string.len(value), value); "
                         + "local key = ARGV[i-1];"
                         + "redis.call('hmset', KEYS[1], key, val); "
-                        
+
                         + "local msg = struct.pack('Lc0Lc0', string.len(key), key, string.len(value), value); "
                         + "redis.call('publish', KEYS[2], msg); "
                     + "end;"
                 + "end;",
             Arrays.<Object>asList(getName(), getCreatedChannelName()), params.toArray());
     }
-    
+
     @Override
     public int addListener(final MapEntryListener listener) {
         if (listener == null) {
             throw new NullPointerException();
         }
-        
+
         if (listener instanceof EntryRemovedListener) {
             RTopic<List<Object>> topic = redisson.getTopic(getRemovedChannelName(), new MapCacheEventCodec(codec));
             return topic.addListener(new MessageListener<List<Object>>() {
@@ -1335,7 +1625,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                 }
             });
         }
-        
+
         if (listener instanceof EntryCreatedListener) {
             RTopic<List<Object>> topic = redisson.getTopic(getCreatedChannelName(), new MapCacheEventCodec(codec));
             return topic.addListener(new MessageListener<List<Object>>() {
@@ -1346,7 +1636,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                 }
             });
         }
-        
+
         if (listener instanceof EntryUpdatedListener) {
             RTopic<List<Object>> topic = redisson.getTopic(getUpdatedChannelName(), new MapCacheEventCodec(codec));
             return topic.addListener(new MessageListener<List<Object>>() {
@@ -1357,7 +1647,7 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                 }
             });
         }
-        
+
         if (listener instanceof EntryExpiredListener) {
             RTopic<List<Object>> topic = redisson.getTopic(getExpiredChannelName(), new MapCacheEventCodec(codec));
             return topic.addListener(new MessageListener<List<Object>>() {
@@ -1368,60 +1658,70 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                 }
             });
         }
-        
+
         throw new IllegalArgumentException("Wrong listener type " + listener.getClass());
     }
-    
+
     @Override
     public void removeListener(int listenerId) {
         RTopic<List<Object>> removedTopic = redisson.getTopic(getRemovedChannelName(), new MapCacheEventCodec(codec));
         removedTopic.removeListener(listenerId);
-        
+
         RTopic<List<Object>> createdTopic = redisson.getTopic(getCreatedChannelName(), new MapCacheEventCodec(codec));
         createdTopic.removeListener(listenerId);
-        
+
         RTopic<List<Object>> updatedTopic = redisson.getTopic(getUpdatedChannelName(), new MapCacheEventCodec(codec));
         updatedTopic.removeListener(listenerId);
-        
+
         RTopic<List<Object>> expiredTopic = redisson.getTopic(getExpiredChannelName(), new MapCacheEventCodec(codec));
         expiredTopic.removeListener(listenerId);
     }
 
     @Override
     public RFuture<Boolean> deleteAsync() {
-        return commandExecutor.writeAsync(getName(), RedisCommands.DEL_OBJECTS, getName(), getTimeoutSetName(), getIdleSetName());
+        return commandExecutor.writeAsync(getName(), RedisCommands.DEL_OBJECTS, getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName());
     }
 
     @Override
     public RFuture<Boolean> expireAsync(long timeToLive, TimeUnit timeUnit) {
         return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
-                "redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag');" +
-                "redis.call('pexpire', KEYS[2], ARGV[1]); " +
-                "redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag');" +
-                "redis.call('pexpire', KEYS[3], ARGV[1]); " +
-                "return redis.call('pexpire', KEYS[1], ARGV[1]); ",
-                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName()), timeUnit.toMillis(timeToLive));
+                "local maxSize = tonumber(ARGV[2]);" +
+                        "if maxSize ~= 0 then" +
+                        "    redis.call('pexpire', KEYS[4], ARGV[1]);" +
+                        "end;" +
+                        "redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag');" +
+                        "redis.call('pexpire', KEYS[2], ARGV[1]); " +
+                        "redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag');" +
+                        "redis.call('pexpire', KEYS[3], ARGV[1]); " +
+                        "return redis.call('pexpire', KEYS[1], ARGV[1]); ",
+                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()),
+                timeUnit.toMillis(timeToLive), maxSize);
     }
 
     @Override
     public RFuture<Boolean> expireAtAsync(long timestamp) {
         return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
-                "redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag');" +
-                "redis.call('pexpireat', KEYS[2], ARGV[1]); " +
-                "redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag');" +
-                "redis.call('pexpire', KEYS[3], ARGV[1]); " +
-                "return redis.call('pexpireat', KEYS[1], ARGV[1]); ",
-                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName()), timestamp);
+                "local maxSize = tonumber(ARGV[2]);" +
+                        "if maxSize ~= 0 then" +
+                        "   redis.call('pexpire', KEYS[4], ARGV[1]);" +
+                        "end;" +
+                        "redis.call('zadd', KEYS[2], 92233720368547758, 'redisson__expiretag');" +
+                        "redis.call('pexpireat', KEYS[2], ARGV[1]); " +
+                        "redis.call('zadd', KEYS[3], 92233720368547758, 'redisson__expiretag');" +
+                        "redis.call('pexpire', KEYS[3], ARGV[1]); " +
+                        "return redis.call('pexpireat', KEYS[1], ARGV[1]); ",
+                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()),
+                timestamp, maxSize);
     }
 
     @Override
     public RFuture<Boolean> clearExpireAsync() {
         return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
-                  "redis.call('zrem', KEYS[2], 'redisson__expiretag'); " +
-                  "redis.call('persist', KEYS[2]); " +
-                  "redis.call('zrem', KEYS[3], 'redisson__expiretag'); " +
-                  "redis.call('persist', KEYS[3]); " +
-                  "return redis.call('persist', KEYS[1]); ",
+                "redis.call('zrem', KEYS[2], 'redisson__expiretag'); " +
+                        "redis.call('persist', KEYS[2]); " +
+                        "redis.call('zrem', KEYS[3], 'redisson__expiretag'); " +
+                        "redis.call('persist', KEYS[3]); " +
+                        "return redis.call('persist', KEYS[1]); ",
                 Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName()));
     }
 
@@ -1429,36 +1729,41 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     public RFuture<Set<K>> readAllKeySetAsync() {
         return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_MAP_KEY_SET,
                 "local s = redis.call('hgetall', KEYS[1]); "
-                + "local result = {}; "
-                + "for i, v in ipairs(s) do "
-                    + "if i % 2 == 0 then "
-                      + "local t, val = struct.unpack('dLc0', v); "
-                      + "local key = s[i-1];" +
-                        "local expireDate = 92233720368547758; " +
-                        "local expireDateScore = redis.call('zscore', KEYS[2], key); "
-                        + "if expireDateScore ~= false then "
-                            + "expireDate = tonumber(expireDateScore) "
-                        + "end; "
-                        + "if t ~= 0 then "
-                            + "local expireIdle = redis.call('zscore', KEYS[3], key); "
-                            + "if expireIdle ~= false then "
+                        + "local result = {}; "
+                        + "for i, v in ipairs(s) do "
+                            + "if i % 2 == 0 then "
+                                + "local t, val = struct.unpack('dLc0', v); "
+                                + "local key = s[i-1];" +
+                                "local expireDate = 92233720368547758; " +
+                                "local expireDateScore = redis.call('zscore', KEYS[2], key); "
+                                + "if expireDateScore ~= false then "
+                                + "expireDate = tonumber(expireDateScore) "
+                                + "end; "
+                                + "if t ~= 0 then "
+                                + "local expireIdle = redis.call('zscore', KEYS[3], key); "
+                                + "if expireIdle ~= false then "
                                 + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
                                     + "local value = struct.pack('dLc0', t, string.len(val), val); "
                                     + "redis.call('hset', KEYS[1], key, value); "
                                     + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); "
+                                    + "local maxSize = tonumber(ARGV[2]);"
+                                    + "if maxSize ~= 0 then"
+                                    + "   redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key);"
+                                    + "end;"
                                 + "end; "
                                 + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                                + "end; "
+                                + "end; "
+                                + "if expireDate > tonumber(ARGV[1]) then "
+                                    + "table.insert(result, key); "
+                                + "end; "
                             + "end; "
-                        + "end; "
-                        + "if expireDate > tonumber(ARGV[1]) then "
-                            + "table.insert(result, key); "
-                        + "end; "
-                    + "end; "
-               + "end;" +
-             "return result;",
-             Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName()), System.currentTimeMillis());
+                        + "end;" +
+                        "return result;",
+                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()),
+                System.currentTimeMillis(), maxSize);
     }
-    
+
     @Override
     public RFuture<Set<java.util.Map.Entry<K, V>>> readAllEntrySetAsync() {
         return readAll(RedisCommands.EVAL_MAP_ENTRY);
@@ -1467,35 +1772,40 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     private <R> RFuture<R> readAll(RedisCommand<?> evalCommandType) {
         return commandExecutor.evalWriteAsync(getName(), codec, evalCommandType,
                 "local s = redis.call('hgetall', KEYS[1]); "
-                + "local result = {}; "
-                + "for i, v in ipairs(s) do "
-                    + "if i % 2 == 0 then "
-                      + "local t, val = struct.unpack('dLc0', v); "
-                      + "local key = s[i-1];" +
-                        "local expireDate = 92233720368547758; " +
-                        "local expireDateScore = redis.call('zscore', KEYS[2], key); "
-                        + "if expireDateScore ~= false then "
-                            + "expireDate = tonumber(expireDateScore) "
-                        + "end; "
-                        + "if t ~= 0 then "
-                            + "local expireIdle = redis.call('zscore', KEYS[3], key); "
-                            + "if expireIdle ~= false then "
-                                + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
-                                    + "local value = struct.pack('dLc0', t, string.len(val), val); "
-                                    + "redis.call('hset', KEYS[1], key, value); "
-                                    + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); "
+                        + "local result = {}; "
+                        + "for i, v in ipairs(s) do "
+                            + "if i % 2 == 0 then "
+                                + "local t, val = struct.unpack('dLc0', v); "
+                                + "local key = s[i-1];" +
+                                "local expireDate = 92233720368547758; " +
+                                "local expireDateScore = redis.call('zscore', KEYS[2], key); "
+                                + "if expireDateScore ~= false then "
+                                    + "expireDate = tonumber(expireDateScore) "
+                                + "end; "
+                                + "if t ~= 0 then "
+                                    + "local expireIdle = redis.call('zscore', KEYS[3], key); "
+                                    + "if expireIdle ~= false then "
+                                        + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
+                                            + "local value = struct.pack('dLc0', t, string.len(val), val); "
+                                            + "redis.call('hset', KEYS[1], key, value); "
+                                            + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); "
+                                            + "local maxSize = tonumber(ARGV[2]);"
+                                            + "if maxSize ~= 0 then"
+                                            + "   redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key);"
+                                            + "end;"
+                                        + "end; "
+                                        + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
+                                    + "end; "
+                                + "end; "
+                                + "if expireDate > tonumber(ARGV[1]) then "
+                                    + "table.insert(result, key); "
+                                    + "table.insert(result, val); "
                                 + "end; "
-                                + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
                             + "end; "
-                        + "end; "
-                        + "if expireDate > tonumber(ARGV[1]) then "
-                            + "table.insert(result, key); "
-                            + "table.insert(result, val); "
-                        + "end; "
-                    + "end; "
-               + "end;" +
-             "return result;",
-             Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName()), System.currentTimeMillis());
+                        + "end;" +
+                        "return result;",
+                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()),
+                System.currentTimeMillis(), maxSize);
     }
 
     @Override
@@ -1508,23 +1818,27 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
     public RFuture<Collection<V>> readAllValuesAsync() {
         return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_MAP_VALUE_LIST,
                 "local s = redis.call('hgetall', KEYS[1]); "
-                + "local result = {}; "
-                + "for i, v in ipairs(s) do "
-                    + "if i % 2 == 0 then "
-                      + "local t, val = struct.unpack('dLc0', v); "
-                      + "local key = s[i-1];" +
-                        "local expireDate = 92233720368547758; " +
-                        "local expireDateScore = redis.call('zscore', KEYS[2], key); "
-                        + "if expireDateScore ~= false then "
-                            + "expireDate = tonumber(expireDateScore) "
-                        + "end; "
-                        + "if t ~= 0 then "
+                    + "local result = {}; "
+                    + "for i, v in ipairs(s) do "
+                        + "if i % 2 == 0 then "
+                            + "local t, val = struct.unpack('dLc0', v); "
+                            + "local key = s[i-1];" +
+                            "local expireDate = 92233720368547758; " +
+                            "local expireDateScore = redis.call('zscore', KEYS[2], key); "
+                            + "if expireDateScore ~= false then "
+                                + "expireDate = tonumber(expireDateScore) "
+                            + "end; "
+                            + "if t ~= 0 then "
                             + "local expireIdle = redis.call('zscore', KEYS[3], key); "
                             + "if expireIdle ~= false then "
                                 + "if tonumber(expireIdle) > tonumber(ARGV[1]) then "
                                     + "local value = struct.pack('dLc0', t, string.len(val), val); "
                                     + "redis.call('hset', KEYS[1], key, value); "
                                     + "redis.call('zadd', KEYS[3], t + tonumber(ARGV[1]), key); "
+                                    + "local maxSize = tonumber(ARGV[2]);"
+                                    + "if maxSize ~= 0 then"
+                                    + "   redis.call('zadd', KEYS[4], tonumber(ARGV[1]), key);"
+                                    + "end;"
                                 + "end; "
                                 + "expireDate = math.min(expireDate, tonumber(expireIdle)) "
                             + "end; "
@@ -1532,9 +1846,10 @@ public class RedissonMapCache<K, V> extends RedissonMap<K, V> implements RMapCac
                         + "if expireDate > tonumber(ARGV[1]) then "
                             + "table.insert(result, val); "
                         + "end; "
-                    + "end; "
-               + "end;" +
-             "return result;",
-             Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName()), System.currentTimeMillis());
+                        + "end; "
+                    + "end;" +
+                    "return result;",
+                Arrays.<Object>asList(getName(), getTimeoutSetName(), getIdleSetName(), getLastAccessTimeSetName()),
+                System.currentTimeMillis(), maxSize);
     }
 }
diff --git a/redisson/src/main/java/org/redisson/api/MapOptions.java b/redisson/src/main/java/org/redisson/api/MapOptions.java
index 0f49a3fcb..2b45a69ba 100644
--- a/redisson/src/main/java/org/redisson/api/MapOptions.java
+++ b/redisson/src/main/java/org/redisson/api/MapOptions.java
@@ -49,6 +49,7 @@ public class MapOptions<K, V> {
     private MapWriter<K, V> writer;
     private WriteMode writeMode = WriteMode.WRITE_THROUGH;
     private int writeBehindThreads = 1;
+    private int maxSize = 0;
     
     protected MapOptions() {
     }
@@ -134,5 +135,20 @@ public class MapOptions<K, V> {
     public MapLoader<K, V> getLoader() {
         return loader;
     }
-    
+
+    /**
+     * Sets max size of the map.
+     * <p>
+     * Currently only RedissonMapCache is supported.
+     *
+     * @param maxSize - max size
+     * @return MapOptions instance
+     */
+    public MapOptions<K, V> maxSize(int maxSize) {
+        this.maxSize = maxSize;
+        return this;
+    }
+    public int getMaxSize() {
+        return maxSize;
+    }
 }
diff --git a/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java b/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java
index b6fbecb57..f01e96325 100644
--- a/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java
+++ b/redisson/src/test/java/org/redisson/RedissonMapCacheTest.java
@@ -215,6 +215,31 @@ public class RedissonMapCacheTest extends BaseMapTest {
         expected.put("3", "33");
         assertThat(store).isEqualTo(expected);
     }
+
+    @Test
+    public void testFastPutMaxSize() {
+        final int maxSize = 2;
+        Map<String, String> store = new LinkedHashMap<String, String>() {
+            @Override
+            protected boolean removeEldestEntry(Entry<String, String> eldest) {
+                return size() > maxSize;
+            }
+        };
+        MapOptions<String, String> options = MapOptions.<String, String>defaults().writer(createMapWriter(store));
+        options.maxSize(maxSize);
+        RMapCache<String, String> map = redisson.getMapCache("test", options);
+
+        map.fastPut("1", "11", 10, TimeUnit.SECONDS);
+        map.fastPut("2", "22", 10, TimeUnit.SECONDS);
+        map.fastPut("3", "33", 10, TimeUnit.SECONDS);
+
+        assertThat(map.size()).isEqualTo(maxSize);
+
+        Map<String, String> expected = new HashMap<>();
+        expected.put("2", "22");
+        expected.put("3", "33");
+        assertThat(store).isEqualTo(expected);
+    }
     
     @Test
     public void testOrdering() {