zoukankan      html  css  js  c++  java
  • 频繁调用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

  • 相关阅读:
    jsp生成xml文件示例
    jsp分页显示
    Spring AOP学习笔记
    让leeon不再眷念马桶——书评《精通正则表达式》
    用JSP实现上传文件的两种方法
    oracle sql性能优化
    Iron Speed Designer 4.2.2学习
    再议《JavaScript代码优化一例》
    有关《大道至简》的几点讨论~
    有源则至清——我读《移山之道》
  • 原文地址:https://www.cnblogs.com/zendwang/p/concurrentlinkedqueue-repeated-call-offer-remove-memory-leak.html
Copyright © 2011-2022 走看看