栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Redis内存淘汰策略

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Redis内存淘汰策略

一:Redis最大占用内存

打开redis的redis.conf配置文件,设置maxmemory参数,注意maxmemory是byte字节类型。

如果不设置最大内存大小或者设置最大内存大小为0,在64位操作系统下不限制内存大小,在32位

操作系统下最多使用3GB内存。一般推荐Redis设置内存为最大物理内存的的四分之三。

 如何修改reids内存设置?

1.手动进入redis.conf配置文件修改

2.通过命令修改

 查看redis内存使用情况命令:info memory

二:Redis内存使用超出了设置的最大值会怎样?

我们可以故意将redis内存设置一个字节模拟一下

 然后进入redis随便设置一个值就会报OOM

 所以为了不报OOM,才会有内存淘汰策略去杜绝内存打满。

三:内存淘汰策略

首先,我们有必要了解一下redis的过期策略。

在Redis中过期的key不会立刻从内存中删除,而是会同时以下面两种策略进行删除:

惰性删除:当key被访问时检查该key的过期时间,若已过期则删除;已过期未被访问的数据仍保持在内存中,消耗内存资源;
定期删除:每隔一段时间,随机检查设置了过期的key并删除已过期的key;维护定时器消耗CPU资源;

以上两种的过期策略都有各自的缺陷,所以redis提供了内存淘汰策略来进行补充。
8中策略:

1. noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键

2. allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键

3. volatile-lru:加入键的时候如果过限,首先从设置了过期时间的键集合中驱逐最久没有使用的键

4. allkeys-random:加入键的时候如果过限,从所有key随机删除

5. volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐

6. volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键

7. volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键

8. allkeys-lfu:从所有键中驱逐使用频率最少的键

redis默认使用的noeviction,推荐使用allkeys-lru

四:LRU

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法。

LRU的算法核心是哈希链表(hashmap + DoublelinkedList),查找用哈希,增删用链表,能很好的满足查找增删都是o(1)。

利用linkedHashMap手写LRU算法:

public class LRUDemo extends linkedHashMap {
  private int capacity;
  public LRUDemo(int capacity) {
    //accessOrder参数要设置为true,不然不会将最近使用顶到后面去
    super(capacity,0.75F,true);
    this.capacity = capacity;
  }

  @Override
  protected boolean removeEldestEntry(Entry eldest) {
    return super.size() > capacity;
  }

  public static void main(String[] args) {
    LRUDemo lruDemo = new LRUDemo(3);
    lruDemo.put(1,"a");
    lruDemo.put(2,"b");
    lruDemo.put(3,"c");
    System.out.println(lruDemo.keySet());
    lruDemo.put(4,"d");
    System.out.println(lruDemo.keySet());
    lruDemo.get(3);
    System.out.println(lruDemo.keySet());
    lruDemo.get(3);
    System.out.println(lruDemo.keySet());
    lruDemo.get(2);
    System.out.println(lruDemo.keySet());
  }
}

打印结果:

从结果可以看出,当容器已满的时候再向容器新增数据时,会删除掉排在第一个位置的数据,且当一个数据被最近使用时,会将这个数据排到末尾(这与accessOrder参数设置为true有关)

 完全手写LRU算法:

// map 负责查找,构建一个虚拟的双向链表,它里面安装的是一个个的node节点,作为数据载体
public class LRUCacheDemo {

  //1.构建一个Node节点,作为数据载体
  class Node {
    K key;
    V value;
    Node prev;
    Node next;

    public Node() {
      this.prev = this.next = null;
    }

    public Node(K key,V value) {
      this.key = key;
      this.value = value;
      this.prev = this.next = null;
    }
  }

  //2.构建一个虚拟的双向列表,里面放的就是我们的Node
  class DoublelinkedList {
    Node head;
    Node tail;

    public DoublelinkedList() {
      head = new Node<>();
      tail = new Node<>();
      head.next = tail;
      tail.prev = head;
    }

    //添加到头
    public void addHead(Node node) {
      node.next = head.next;
      node.prev = head;
      head.next.prev = node;
      head.next = node;
    }

    //删除节点
    public void removeNode(Node node) {
      node.next.prev = node.prev;
      node.prev.next = node.next;
      node.prev = null;
      node.next = null;
    }

    //获得最后一个节点
    public Node getLastNode() {
      return tail.prev;
    }
  }

  private int cacheSize;
  Map> map;
  DoublelinkedList doublelinkedList;

  public LRUCacheDemo(int cacheSize) {
    this.cacheSize = cacheSize;
    map = new HashMap<>();
    doublelinkedList = new DoublelinkedList<>();
  }

  public Object get(Object key) {
    if (!map.containsKey(key)) {
      return -1;
    }
    Node node = map.get(key);
    doublelinkedList.removeNode(node);
    doublelinkedList.addHead(node);
    return node.value;
  }

  public void put(Object key, Object value) {
    // 已经存在这个key,执行更新操作
    if (map.containsKey(key)) {
      Node node = map.get(key);
      node.value = value;
      map.put(key,node);
      doublelinkedList.removeNode(node);
      doublelinkedList.addHead(node);
    } else {
      // 容器满了
      if (map.size() == cacheSize) {
        Node lastNode = doublelinkedList.getLastNode();
        map.remove(lastNode.key);
        doublelinkedList.removeNode(lastNode);
      }
      // 新增
      Node newNode = new Node<>(key, value);
      map.put(key,newNode);
      doublelinkedList.addHead(newNode);
    }
  }

  public static void main(String[] args) {
    LRUCacheDemo lruCacheDemo = new LRUCacheDemo(3);
    lruCacheDemo.put(8,1);
    lruCacheDemo.put(6,2);
    lruCacheDemo.put(7,3);
    System.out.println(lruCacheDemo.map.keySet());
    lruCacheDemo.put(4,4);
    System.out.println(lruCacheDemo.map.keySet());
    lruCacheDemo.put(6,5);
    System.out.println(lruCacheDemo.map.keySet());
    lruCacheDemo.put(5,5);
    System.out.println(lruCacheDemo.map.keySet());
    lruCacheDemo.put("a",5);
    System.out.println(lruCacheDemo.map.keySet());
  }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/319144.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号