3

我对 Java 中的 GC 有一个非常奇怪的问题。我正在运行以下代码:

 while(some condition){
        //do a lot of work...
        logger.info("Generating resulting time series...");
        Collection<MetricTimeSeries> allSeries = manager.getTimeSeries();
        logger.info(String.format("Generated %,d time series! Storing in files now...", allSeries.size()));

        //for (MetricTimeSeries series : allSeries) {
           // just empty loop
        //}
 }

当我查看 JConsole 时,在每次循环迭代重新启动时,如果我手动强制 GC,我的旧 gen 堆空间会占用大约 90 MB 的大小。如果我取消注释循环,就像这样

 while(some condition){
        //do a lot of work...
        logger.info("Generating resulting time series...");
        Collection<MetricTimeSeries> allSeries = manager.getTimeSeries();
        logger.info(String.format("Generated %,d time series! Storing in files now...", allSeries.size()));

        for (MetricTimeSeries series : allSeries) {
           // just empty loop
        }
 }

即使我强制它刷新,它也不会低于 550MB。根据 yourKit profiler,TimeSeries 对象可以通过主线程的本地 var(集合)访问,就在 GC 重新启动新迭代之后......而且集合很大(250K 时间序列。)...... Wyy 是这种情况发生了,我该如何“对抗”这种(不正确的?)行为?

4

2 回答 2

2

是的,垃圾收集器可能很神秘......但它胜过管理你自己的内存;)

Collections 和 Maps 有一种方法可以比您希望的更长时间地挂起引用从而在您可能期望的时候防止垃圾收集。正如您所注意到的,设置allSeries对自身的引用null会将其标记为垃圾收集,因此它的内容也可供抓取。另一种方法是调用allSeries.clear():这将取消所有MetricTimeSeries对象的链接,并且它们将免费用于垃圾收集。

为什么删除循环也能解决这个问题?这是更有趣的问题。我很想建议编译器正在优化对allSeries.. 的引用,但您仍在调用allSeries.size(),因此它无法完全优化引用。

为了搅浑水,不同的编译(和设置)表现不同,并使用不同的垃圾收集器,它们本身的行为也不同。如果没有更多信息,很难准确地说出幕后发生的事情。

于 2012-12-15T16:26:27.480 回答
1

由于您正在构建一个(大)ArrayList时间序列,因此只要它被引用,它就会占据堆,并且如果它保持足够长的时间(或者如果年轻一代太小而无法实际持有它),它将被提升为老年代。我不确定您如何将您在 JConsole 或 Yourkit 中看到的信息与程序中的特定点相关联,但在通过几次 JIT 传递优化空循环之前,您的while循环将花费更长的时间并保持收集更长时间,这可能解释了感知到的差异,而实际上并没有很多。

这种行为没有什么不正确的。如果你不想消耗这么多内存,你需要改变你的Collection,所以它不是一个热切的填充ArrayList,而是一个惰性集合,更多的是一个流(如果你曾经做过 XML 处理,想想 DOM 与 SAX)哪个在迭代时被评估。如果您不需要对整个集合进行排序,那是可行的,尤其是因为您似乎在说集合是底层对象返回的子集合的串联。

如果您可以将返回类型从Collectionto更改Iterable为,例如,您可以使用GuavaFluentIterable.transformAndConcat()将底层对象的集合转换为延迟评估的Iterable时间序列串联。当然,集合的大小不再直接可用(如果您尝试独立于迭代获取它,您将评估惰性集合两次)。

于 2012-12-16T22:18:45.163 回答