如何在堆中通过许多StackTraceElement模拟完整的gc

时间:2016-01-27 13:58:22

标签: java jvm java.util.concurrent

最近我的操作同事报告生产环境有很多完整的gc,并影响应用程序的响应时间。他提供了一个图像 enter image description here

他特别说StackTraceElement有85M,并建议没有这些代码,例如。

e.printStackTrace();

现在我想在我的本地模拟这种情况,我写了一个类似下面的测试代码

public class FullGCByLogTest {
    private static final Logger log = Logger.getLogger(FullGCByLogTest.class);
    public static final byte[] _1M = new byte[1 * 1024 * 1024]; //placeholder purpose

    public static void main(String[] args) throws InterruptedException {
        int nThreads = 1000; // concurrent count
        ExecutorService pool = Executors.newFixedThreadPool(nThreads);
        while (true) {
            final CountDownLatch latch = new CountDownLatch(nThreads);
            for (int i = 0; i < nThreads; i++) {
                pool.submit(new Runnable() {
                    @Override
                    public void run() {
                        latch.countDown();
                        try {
                            latch.await(); // waiting for execute below code concurrently
                        } catch (InterruptedException e1) {
                        }
                        try {
                            int i = 1 / 0;
                            System.out.println(i);
                        } catch (Exception e) {
                            e.printStackTrace();
                            // log.error(e.getMessage(), e);
                        }

                    }
                });
            }
            try {
                Thread.sleep(100); // interval 1s every concurrent calling
            } catch (InterruptedException e) {
            }
       }

    }
}

我用这些vm args运行这个类

-Xmx4m -Xms4m -XX:NewSize=1m -XX:MaxNewSize=1m -XX:+PrintGCDetails

然后在jvisualvm VisualGC中我发现老版本是7 M,但我设置的最大堆是4米。

enter image description here

另外在heapdump中我没有找到StackTraceElement。那么我怎么能成功地模拟这个问题呢?

enter image description here

1 个答案:

答案 0 :(得分:3)

在实例化异常对象时实际创建StackTraceElement个对象,一旦异常对象无法访问,它们就有资格进行垃圾回收。

我怀疑你的(明显的)存储泄漏的真正原因是你的代码中存在大量异常对象。

调用printStackTrace()不会泄漏对象。你的同事误解了这个问题。但是,在整个地方调用printStackTrace()是丑陋的...如果经常发生,那将导致性能问题。

您的模拟和结果是一个红色的鲱鱼,但是堆大于您要求的可能原因是JVM已经“舍入”到更大的堆大小。 (4Mb是一个微不足道的堆大小,对大多数Java程序来说都是不切实际的。)

  

那我怎么能成功地模仿这个问题呢?

仿真极不可能告诉你任何有用的东西。您需要从生产系统中获取堆转储并进行分析。