最近我的操作同事报告生产环境有很多完整的gc,并影响应用程序的响应时间。他提供了一个图像
他特别说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米。
另外在heapdump中我没有找到StackTraceElement。那么我怎么能成功地模拟这个问题呢?
答案 0 :(得分:3)
在实例化异常对象时实际创建StackTraceElement
个对象,一旦异常对象无法访问,它们就有资格进行垃圾回收。
我怀疑你的(明显的)存储泄漏的真正原因是你的代码中存在大量异常对象。
调用printStackTrace()
不会泄漏对象。你的同事误解了这个问题。但是,在整个地方调用printStackTrace()
是丑陋的...如果经常发生,那将导致性能问题。
您的模拟和结果是一个红色的鲱鱼,但是堆大于您要求的可能原因是JVM已经“舍入”到更大的堆大小。 (4Mb是一个微不足道的堆大小,对大多数Java程序来说都是不切实际的。)
那我怎么能成功地模仿这个问题呢?
仿真极不可能告诉你任何有用的东西。您需要从生产系统中获取堆转储并进行分析。