Java GC 在最小分配后运行非常频繁

标签 java android eclipse debugging

我正在为 android 编写一个实时游戏,因此我想按照 android“为性能而设计”开发人员指南中的建议尽可能减少分配/垃圾收集。

我有一个非常简单的游戏,它没有使用太多内存(根据 hprof 堆转储,<2-3% 的堆),但我的并发 gc 每 7 秒运行一次,总是释放大约 1MB 的内存。我的游戏完全暂停并且没有做任何有趣的事情,并且运行分配跟踪器 5 秒显示分配很少。这是打开几秒钟后分配跟踪器转储的全部内容,看起来占不到 1kb 的分配(主要是 dalvik 的东西和我的锁的锁定/解锁方法)。

19  24  byte[]  5   dalvik.system.NativeStart   run 
18  12  java.lang.Integer   5   java.lang.Integer   valueOf 
17  24  org.apache.harmony.dalvik.ddmc.Chunk    5   org.apache.harmony.dalvik.ddmc.DdmServer    dispatch    
16  17  byte[]  5   android.ddm.DdmHandleHeap   handleREAQ  
15  24  org.apache.harmony.dalvik.ddmc.Chunk    5   android.ddm.DdmHandleHeap   handleREAQ  
14  28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
13  28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
12  28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
11  28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
10  28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
9   28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
8   28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
7   28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
6   28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
5   28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
4   28  java.util.concurrent.locks.AbstractQueuedSynchronizer$Node  10  java.util.concurrent.locks.AbstractQueuedSynchronizer   addWaiter   
3   24  byte[]  5   dalvik.system.NativeStart   run 
2   12  java.lang.Integer   5   java.lang.Integer   valueOf 
1   24  org.apache.harmony.dalvik.ddmc.Chunk    5   org.apache.harmony.dalvik.ddmc.DdmServer    dispatch    

尽管如此,我仍然每隔几秒就会看到大约 1MB 的集合:

03-09 21:41:56.665: D/dalvikvm(4210): GC_CONCURRENT freed 934K, 58% free 3069K/7175K, external 2847K/3550K, paused 3ms+2ms
03-09 21:42:03.685: D/dalvikvm(4210): GC_CONCURRENT freed 937K, 58% free 3069K/7175K, external 2847K/3550K, paused 3ms+1ms
03-09 21:42:10.705: D/dalvikvm(4210): GC_CONCURRENT freed 937K, 58% free 3069K/7175K, external 2847K/3550K, paused 5ms+2ms
03-09 21:42:17.715: D/dalvikvm(4210): GC_CONCURRENT freed 934K, 58% free 3069K/7175K, external 2847K/3550K, paused 3ms+1ms
03-09 21:42:24.725: D/dalvikvm(4210): GC_CONCURRENT freed 934K, 58% free 3069K/7175K, external 2847K/3550K, paused 2ms+3ms

我知道时间不多了,但如果可以避免的话,我不想从我的一个框架中随机窃取 10 毫秒。我的问题是,如果我在分配跟踪器中看不到任何内容,那么什么可以在短短几秒钟内分配这么多内存?我不认为它在手机背景上有任何影响,因为一旦我退出游戏,我就再也看不到 GC(或者很少见)。

我的渲染线程使用 GLSurfaceView,这几乎是唯一在暂停时运行的东西,但我只是对我的内存去向感到困惑。

如有任何想法,我们将不胜感激。

最佳答案

好的,我找到了漏洞。事实证明,我在 float 组上不必要地每帧运行 clone 大约 50 次,但真正让我失望的是这并没有出现在分配跟踪器中。

更多的研究向我展示了这个 thread ,这似乎声称存在一个 android 错误,其中 array.clone() 操作未显示在分配跟踪器中。

很沮丧我花了这么长时间才找到它,但至少现在我每秒只收集 <1kb。

关于Java GC 在最小分配后运行非常频繁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9644271/

相关文章:

android - 导入项目给出了 Unable to resolve target 'android-7'

java - 递归未导航所有子节点

Java Android Date 周五返回错​​误的 GetDay()

android - 如何制作一个 URL,该 URL 将转到浏览器和 Android 应用程序上的 Google Play 音乐搜索

安卓 : which offline maps use in app

android - 测试 Android 应用程序 : Exception during suite construction

java - @BeforeSuite 和 @AfterSuite 必须是静态的吗?

java - 如何使用 Java 读取 .csv 文件并将其数据插入 SQL Server?

java - JSR 107 - 缓存 (JCache) 与 CPU 缓存

java - 在嵌套 Flowable 的 onNext 中抛出异常会导致 UndeliverableException