为什么是锯齿形图?

当我使用 NetBeans 运行下面提到的代码时,分配的堆大小图类似于锯齿形状。我正在附加来自JVisualVM的屏幕截图,它以锯齿形状显示堆分配图。该程序是一个简单的无限循环,将“Hello,World!”打印到控制台中。

public class HelloWorld {
    public static void main(String a[]){
        while(true) {
            System.out.println("Hello, World!");
        }
    }
}

enter image description here谁能解释一下所用堆图形形状背后的原因?

PS:即使我在不使用NetBeans的情况下运行它,也会发生这种情况,因此它很可能与NetBeans无关...


答案 1

堆用法中的锯齿模式可以通过以下事实来解释:在调用调用期间创建了几个局部变量。最值得注意的是,在Oracle/Sun JRE中,在年轻一代中创建了几个实例,如以下使用VisualVM的内存探查器获得的快照所示:System.out.printlnHeapCharBuffer

Visual VM - Memory snapshot

有趣的是堆上存在的活动对象的数量。锯齿图案是由当伊甸园空间填满时发生的年轻一代垃圾收集周期引起的;由于程序中没有执行繁重的计算活动,因此JVM能够执行循环的多次迭代,从而导致伊甸园空间(大小为4MB)填满。然后,随后的年轻一代收集周期清除了大部分垃圾;它几乎总是整个伊甸园空间,除非对象仍在使用中,如从 VisualVM 获得的以下 gc 跟踪所示:

Visual VM GC probes

因此,锯齿图案的行为可以通过一系列快速连续的对象分配来解释,这些对象填充了伊甸园空间,触发了年轻的垃圾回收周期;此进程循环重复,没有延迟,因为底层 JVM 进程不会被另一个进程抢占,并且 JVM 中负责对象分配的主线程也不会被另一个线程抢占。


答案 2

任何以常规速率分配对象的进程都将导致堆内存消耗的稳定增加,然后在垃圾回收器收集不再使用的对象时出现瞬时丢弃,从而产生锯齿形。

如果您想知道为什么您的 java 进程在写入 时保持分配内存,请记住,其他线程(例如,将当前内存统计信息提供给 JVisualVM 的线程)可能是分配内存的线程。System.out


推荐