GC运行太频繁



这是一个一般性问题。在我的应用程序中,垃圾收集器运行得太频繁(每秒几次),并且没有释放很多内存(少于1Mb)。问题是,堆大小不再增长了。它大约需要40Mb,有时在其他手机上需要60Mb,其中应用程序的最大容量是128Mb (Galaxy S4)或196Mb (Nexus 4)。

为什么GC运行这么频繁?

下面是GC过于频繁运行时的部分日志。应用程序正在冻结。我什么都没做,我只是试着放大地图。

06-07 16:50:52.003: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60015K/72980K, paused 51ms, total 51ms
06-07 16:50:52.053: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60016K/72980K, paused 51ms, total 51ms
06-07 16:50:52.113: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60016K/72980K, paused 52ms, total 52ms
06-07 16:50:52.163: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60017K/72980K, paused 52ms, total 52ms
06-07 16:50:52.213: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60017K/72980K, paused 51ms, total 52ms
06-07 16:50:52.273: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60018K/72980K, paused 51ms, total 51ms
06-07 16:50:52.324: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60018K/72980K, paused 51ms, total 51ms
06-07 16:50:52.374: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60019K/72980K, paused 52ms, total 52ms
06-07 16:50:52.434: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60019K/72980K, paused 53ms, total 53ms
06-07 16:50:52.484: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60020K/72980K, paused 52ms, total 52ms
06-07 16:50:52.544: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60020K/72980K, paused 56ms, total 56ms
06-07 16:50:52.594: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60021K/72980K, paused 52ms, total 52ms
06-07 16:50:52.654: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60021K/72980K, paused 52ms, total 52ms
06-07 16:50:52.704: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60022K/72980K, paused 52ms, total 52ms
06-07 16:50:52.754: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60022K/72980K, paused 52ms, total 52ms
06-07 16:50:52.814: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60023K/72980K, paused 52ms, total 52ms
06-07 16:50:52.864: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 6023K/72980K, paused 51ms, total 51ms
06-07 16:50:52.924: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60024K/72980K, paused 55ms, total 56ms
06-07 16:50:52.974: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60024K/72980K, paused 52ms, total 52ms
06-07 16:50:53.024: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60025K/72980K, paused 52ms, total 52ms

你的问题与Google Maps Android API如何工作以及应用程序分配多少内存有关。

40-60 MB可能会有问题,因为执行单个GCollection需要更长的时间。作为旁注:我注意到当分配15 MB时添加1000个标记比分配5 MB时花费的时间要长得多。

除此之外,每个对Google Play Services api的调用都在进行IPC,这反过来又会根据这个答案强制GC。这种IPC调用可能在平移或缩放时完成。

GC在需要的时候运行。通常,(即使在DVM上)它确实比您更清楚何时需要运行。如果你认为这个问题不是GC的问题,而是应用程序内存的问题,它可能会帮助你找到解决方案。

频繁gc最有可能的原因是内存快用完了。例如,如果您分配了许多短寿命对象,就可能发生这种情况:您快速地分配了它们,但很快就会忘记它们。每次GC运行时,它都会成功地恢复足够的内存供应用程序继续运行…但很快,你又把记忆填满了。

如果这是实际发生的事情,那么,如果你有更多的内存,就像@parry建议的那样,你只会延迟这个问题。gc的发生频率会降低,但运行时间会更长(因为它们会收集更多的垃圾)。这可能是足够的,但也可能不够。

检查你是否在一个经常被调用的例程中分配对象(例如,你的draw例程)

如果您认为GC的行为很愚蠢(很有可能),并且VM有更多的内存可以空闲,那么您可以尝试通过请求一次性的1/5/10 MB分配来强迫它增加堆大小(使用OOME的try-catch来保护它)。这可能会导致GC在每个周期中清理更多,或者增加发生完整GC的机会。
另一种在PC上工作的启发式方法是在循环中调用System.GC() x次以触发完整的GC。总而言之,这是我自己遇到的,它很糟糕。

最新更新