我有三个对象:
ClassA classA = new ClassA();
ClassA classB = new ClassA();
ClassA classC = new ClassA();
这些对象中的每一个都有一个称为run
的public void
,它做一些事情,并以以下方式调用:
classA.run();
classB.run();
classC.run();
在每个循环迭代中,每个run
调用都会生成特定数量的垃圾。
如何准确确定每个run
生成的垃圾量?
通常(如果您可以这样说OP的用例),您使用profilers/logging来估计分配压力。例如,JRockit任务控制(与JDK 7u40一起使用!)可以转储当前的分配速率。连续进行run
,可以得到每个run
调用的分配速率的估计值。确保严格测量run
呼叫率,因为此时您正在处理基准测试。以jmh为例。
然而,这很无聊。对于完全不同的东西,我有一个棘手(但有趣!)的建议。由于在包括HotSpot在内的大多数现代虚拟机中,新对象都是在线程本地分配缓冲区(TLAB)中线性分配的,因此可以获得地址标记,执行run()
,然后获得另一个地址标记,减去两个标记,并获得调用期间TLAB中浪费的空间量。
事实上,在jol
中,我们有一个有趣的例子,几乎正是这样做的。
有一个鲜为人知的JVM选项-Xafrof,它报告每个类的全局分配总数。我们创建了一个内部开源的"aprof"工具,用于报告每个类的每个方法的分配率:https://code.devexperts.com/display/AProf/
它通过实时修改字节代码来执行对象分配跟踪,并试图平衡性能影响及其报告的深度和精度。它确实显著增加了应用程序的启动时间,但对运行时性能的影响可以忽略不计,因此我们可以在服务器端组件的生产中使用它。
Aprof精确地收集代码中的所有"新"操作,但不收集每个分配的完整堆栈跟踪。它跟踪每个分配操作(类名和方法名)的"位置",同时提供了一种方法,将例如StringBuilder方法中的char[]的分配归因于调用相应StringBuilder方法的实际应用程序代码。它为所有流行的java.lang和java.util类提供了一组合理的默认值,这些类在它们内部分配内存,这样您就可以将实际的应用程序类视为这些分配的最终位置源。
您可以尝试使用内置的探查器VisualVM
来查看细节。
您可以在JDK/bin文件夹中以jvisualvm.exe
或类似名称找到它。
double[] heapFreeSizez = new double[5];
for(int i = 0 ; i < 5 ; ++i) {
heapFreeSizez[i] = 0;
}
heapFreeSizez[0] = (double) Runtime.getRuntime().freeMemory()/1000000.0;
classA.run(); heapFreeSizez[1] = (double) Runtime.getRuntime().freeMemory()/1000000.0;
classB.run(); heapFreeSizez[2] = (double) Runtime.getRuntime().freeMemory()/1000000.0;
classC.run(); heapFreeSizez[3] = (double) Runtime.getRuntime().freeMemory()/1000000.0;
classD.run(); heapFreeSizez[4] = (double) Runtime.getRuntime().freeMemory()/1000000.0;
for(int i = 1 ; i < 5 ; ++i) {
if(heapFreeSizez[i] - heapFreeSizez[i-1] < 0) {
System.out.println(i + "_" + "HELP!");
}
}
可以使用ThreadMXBean#getThreadAllocatedBytes吗?它告诉特定线程分配的内存量。您所需要做的只是测量差异(并考虑getThreadAllocatedBytes
本身产生的8-16字节垃圾)