• 频繁调用ConcurrentLinkedQueue类的offer和remove方法会内存泄露


    频繁调用ConcurrentLinkedQueue类的offer和remove方法会内存泄露
    看一下ConcurrentLinkedQueue类的remove方法

    public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
            implements Queue<E>, java.io.Serializable {
    ....
     public boolean remove(Object o) {
          if (o == null) return false;
          Node<E> pred = null;
          for (Node<E> p = first(); p != null; p = succ(p)) {
              E item = p.item;
              if (item != null &&
                  o.equals(item) &&
                  p.casItem(item, null)) { 
                  Node<E> next = succ(p);
                  if (pred != null && next != null)
                      pred.casNext(p, next);
                  return true;
              }
              pred = p;
          }
          return false;
      }
    ...
    }
    

    调用remove(object) ,当object是最后一个元素,这时候会把该元素设置为null,该元素的next为null,但并不会执行 pred.casNext(p, next);这时候就会导致元素并未从该队列删除。

    该问题在jdk-8u102已解决

    public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
            implements Queue<E>, java.io.Serializable {
    ....
        public boolean remove(Object o) {
            if (o != null) {
                Node<E> next, pred = null;
                for (Node<E> p = first(); p != null; pred = p, p = next) {
                    boolean removed = false;
                    E item = p.item;
                    if (item != null) {
                        if (!o.equals(item)) {
                            next = succ(p);
                            continue;
                        }
                        removed = p.casItem(item, null);
                    }
    
                    next = succ(p);
                    if (pred != null && next != null) // unlink
                        pred.casNext(p, next);
                    if (removed)
                        return true;
                }
            }
            return false;
        }
    ...
    }
    

    在低于jdk-8u102版本测试

    import java.util.Queue;
    import java.util.concurrent.ConcurrentLinkedQueue;
    
    public class ConcurrentLinkedQueueMemoryLeak {
     
        public static void main(String[] args)
        {
            Queue<Object> queue = new ConcurrentLinkedQueue<>();
            queue.offer(new Object());
            
            Object item = new Object();
            
            long iterations = 0;
            try
            {
                while (true)
                {
                    ++iterations;
                    queue.offer(item);
                    queue.remove(item);
                }
            }
            catch (OutOfMemoryError e)
            { 
                queue = null;
                System.err.println("iterations: " + iterations);
                throw e;
            }
        }
    }
    

    设置运行时VM参数:-Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=F:/opt/logs/clq_heapdump.hprof
    设置堆内存为1Mb大小,运行一会就报OOM
    通过Java VIsualVM 打开clq_heapdump.hprof,java,util.currentLinkedQueue$Node实例数24871

  • 相关阅读:
    docker添加sudo权限
    服务器出口ip
    flask
    ACM-奇特的立方体
    ACM-牛喝水
    ACM-可乐兑换
    ACM-Work Assignment
    ACM-DFS Template
    ACM-Checker Challenge
    ACM-Divide Tree
  • 原文地址:https://www.cnblogs.com/zendwang/p/concurrentlinkedqueue-repeated-call-offer-remove-memory-leak.html
Copyright © 2020-2023  润新知