奇怪的堆使用模式
Odd heap usage pattern
我有一个重复的过程:
- 从数据库中获取一些数据
- 在内存中构建一些对象,添加到集合中
- 将集合中的数据写入文件
所有 objects/Collections 超出范围或在每次迭代后设置为 null。 (集合在每次迭代中重复使用。)
使用 Java VisualVM,我看到一个看起来像这样的图表,考虑到这是一个重复的过程,这看起来很奇怪。是的,从数据库返回的数据不一样,但是大体上是一样的数量.
为什么堆大小一开始会变小?
为什么使用的堆与中间的堆大小如此接近?
(在 1:43 处的 ~30 秒的光点正是 VisualVM 暂时冻结的时候)
我不像某些人那样是 GC 专家,但一般的想法是,当您启动程序时,您已经为它指定了初始堆大小、最大堆大小和其他相关参数然后是出发时间。
然而,GC 具有大量的智能和不同的算法,这些算法针对不同类型的任务进行了优化。一个天真的实现只会保持堆大小不变,然后在堆满时收集垃圾。这就是所谓的 "stop the world" 收集,因为收集器需要停止一切以便它可以执行一点(或大)清理。
现代 GC 不仅会导致 运行 程序长时间停顿,因为它需要清理,所以从锯齿波看来,总会有一些清理工作在进行。但是当您启动一个程序时,GC 并不知道该程序将要做什么以及它将如何使用内存。因此它必须观察正在发生的事情,分析内存使用情况,然后决定它需要保留多少内存以供立即使用,是否需要增加当前堆大小或是否可以减少当前堆大小。
根据您的程序行为和所使用的 GC 算法,您可以看到许多不同的模式。只要您没有经历以 OutOfMemoryError
结束的线性增长,您就应该相对安全。当然,除非您想优化正在发生的事情以提高吞吐量、响应能力等,但这是一个更高级的主题,并且当您的代码按照您想要的方式工作时更相关。
我有一个重复的过程:
- 从数据库中获取一些数据
- 在内存中构建一些对象,添加到集合中
- 将集合中的数据写入文件
所有 objects/Collections 超出范围或在每次迭代后设置为 null。 (集合在每次迭代中重复使用。)
使用 Java VisualVM,我看到一个看起来像这样的图表,考虑到这是一个重复的过程,这看起来很奇怪。是的,从数据库返回的数据不一样,但是大体上是一样的数量.
为什么堆大小一开始会变小?
为什么使用的堆与中间的堆大小如此接近?
我不像某些人那样是 GC 专家,但一般的想法是,当您启动程序时,您已经为它指定了初始堆大小、最大堆大小和其他相关参数然后是出发时间。
然而,GC 具有大量的智能和不同的算法,这些算法针对不同类型的任务进行了优化。一个天真的实现只会保持堆大小不变,然后在堆满时收集垃圾。这就是所谓的 "stop the world" 收集,因为收集器需要停止一切以便它可以执行一点(或大)清理。
现代 GC 不仅会导致 运行 程序长时间停顿,因为它需要清理,所以从锯齿波看来,总会有一些清理工作在进行。但是当您启动一个程序时,GC 并不知道该程序将要做什么以及它将如何使用内存。因此它必须观察正在发生的事情,分析内存使用情况,然后决定它需要保留多少内存以供立即使用,是否需要增加当前堆大小或是否可以减少当前堆大小。
根据您的程序行为和所使用的 GC 算法,您可以看到许多不同的模式。只要您没有经历以 OutOfMemoryError
结束的线性增长,您就应该相对安全。当然,除非您想优化正在发生的事情以提高吞吐量、响应能力等,但这是一个更高级的主题,并且当您的代码按照您想要的方式工作时更相关。