23

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

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

在此处输入图像描述 谁能解释已用堆图形形状背后的原因?

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

4

4 回答 4

28

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

视觉 VM - 内存快照

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

Visual VM GC 探测

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

于 2011-08-28T23:19:12.340 回答
7

任何以固定速率分配对象的进程都会导致堆内存消耗的稳定增加,然后当垃圾收集器收集不再使用的对象时会瞬间下降,从而导致锯齿形状。

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

于 2011-08-28T11:39:09.730 回答
1

它可能来自很多地方,并且可能取决于实现。至少以下是可能的(但都只是猜测)

  • 在 System.out.println 下面的流堆栈中的某处有一个字节数组分配(假设输出流的基本方法之一是 write(bytes []b, int off, int len))

  • 这是您正在使用的监控软件使用的开销(我没有使用它)

  • 它是 netbeans VM 中的开销,它最终显示输出

于 2011-08-28T07:23:26.647 回答
1

实际上 jVisualVM 会导致额外的对象分配。jVisualVM 和 jconsole 正在使用 Java 管理扩展。附加到正在运行的应用程序并请求 JVM 指标导致正在创建其他对象。您可以通过添加到您的程序调用来验证这一点

Runtime.getRuntime().freeMemory() 

它报告 JVM 堆中的可用内存。通过运行您的代码,它将显示 [几乎] 没有内存更改,但是一旦您将 jVisualVM 连接到您的程序,您就会看到内存使用量增加。

于 2012-09-12T23:37:37.423 回答