【问题标题】:How do I check if ConcurrentLinkedQueue leaves garbage (dereferenced instances) for the GC?如何检查 ConcurrentLinkedQueue 是否为 GC 留下垃圾(取消引用的实例)?
【发布时间】:2014-08-08 02:16:40
【问题描述】:

我在我的应用程序中使用了一堆ConcurrentLinkedQueues,GC 开销很大。如何检查ConcurrentLinkedQueue 是否是罪魁祸首? Java 中是否有标准方法来分析这些数据结构以进行内存分配/释放?

【问题讨论】:

标签: java memory-management memory-leaks garbage-collection profiling


【解决方案1】:

一种方法是编写一个简单的测试程序并使用-verbose:gc JVM 选项运行它。例如代码:

import java.util.concurrent.ConcurrentLinkedQueue;

public class TestGC {

    public static void main(String[] args) throws Exception {

        final ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<String>();

        String[] strings = new String[1024];

        for(int i = 0; i < strings.length; i++) {
            strings[i] = "string" + i;
        }

        System.gc();
        Thread.sleep(1000);

        System.out.println("Starting...");

        while(true) {
            for(int i = 0; i < strings.length; i++) queue.offer(strings[i]);
            for(int i = 0; i < strings.length; i++) queue.poll();
        }
    }
}

产生输出:

$ java -verbose:gc TestGC
[GC 1352K->560K(62976K), 0.0015210 secs]
[Full GC 560K->440K(62976K), 0.0118410 secs]
Starting...
[GC 17336K->536K(62976K), 0.0005950 secs]
[GC 17432K->536K(62976K), 0.0006130 secs]
[GC 17432K->504K(62976K), 0.0005830 secs]
[GC 17400K->504K(62976K), 0.0010940 secs]
[GC 17400K->536K(77824K), 0.0006540 secs]
[GC 34328K->504K(79360K), 0.0008970 secs]
[GC 35320K->520K(111616K), 0.0008920 secs]
[GC 68104K->520K(111616K), 0.0009930 secs]
[GC 68104K->520K(152576K), 0.0006350 secs]
[GC 109064K->520K(147968K), 0.0007740 secs]
(keeps going forever)

现在,如果您想确切地知道谁是罪魁祸首,您可以使用分析工具。我写了this memory sampler,你可以插入你的代码来快速找出实例是在哪个源代码行中创建的。所以你这样做:

MemorySampler.start();
for(int i = 0; i < strings.length; i++) queue.offer(strings[i]);
for(int i = 0; i < strings.length; i++) queue.poll();
MemorySampler.end();
if (MemorySampler.wasMemoryAllocated()) MemorySampler.printSituation();

当你运行时,你会得到:

Starting...
Memory allocated on last pass: 24576
Memory allocated total: 24576

Stack Trace:
    java.util.concurrent.ConcurrentLinkedQueue.offer(ConcurrentLinkedQueue.java:327)
    TestGC.main(TestGC2.java:25)

从那里您可以看到ConcurrentLinkedQueue 的第 327 行正在泄漏 GC 的实例,换句话说,它没有将它们池化:

public boolean offer(E e) {
    checkNotNull(e);
    final Node<E> newNode = new Node<E>(e);

    for (Node<E> t = tail, p = t;;) {

【讨论】:

  • 感谢您的详细解答。是否可以使用 ConcurrentLinkedQueue 解决这个“问题”?
  • 您可以尝试通过合并Node 实例来修复 ConcurrentLinkedQueue 代码...这不是微不足道的,因为此数据结构高度并发,您将不​​得不围绕您的对象池进行同步,添加锁争用。
  • 希望我能Favorite 一个答案 - 很棒的工具!
【解决方案2】:

尝试使用VisualVM,官方(?)java分析器。玩一会儿。您可以分析正在运行的任何 Java 程序的进程和内存。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-16
    • 2013-11-18
    相关资源
    最近更新 更多