对于应用,我正在努力提高效率非常重要。为了避免不必要的垃圾收集,我分配了大量内存(为了增加堆大小)并立即释放它。但是,无论我有多少可用内存,垃圾收集仍然会发生。
当我不进行额外的内存分配/释放时,我只有24%的可用内存,而下面的日志只有63%,但GC调用的数量是相同的。 GC暂停是相同的。执行时间(程序)是相同的。
任何人都可以解释一下这种古怪的GC行为吗?为什么GC_FOR_ALLOC
会被触发?有大量的空闲记忆。
在我的程序中主要操作有:文件读取,加密,数据传输。
对于数据传输和文件读取,我使用ByteBuffer
和FileChannel
,SocketChannel
。
大量的ByteBuffer分配是否会成为瓶颈?
好像我没有任何内存泄漏。
在GalaxyS3(Android 4.4.2)和GalaxyS2(Android 4.1.2)上进行了程序测试
12-21 00:30:54.973: I/dalvikvm-heap(30222): Grow heap (frag case) to 44.361MB for 25000016-byte allocation
12-21 00:30:55.463: D/dalvikvm(30222): GC_FOR_ALLOC freed 43K, 8% free 42893K/46416K, paused 20ms, total 20ms
12-21 00:31:01.900: D/dalvikvm(30222): GC_FOR_ALLOC freed 28367K, 63% free 18615K/49480K, paused 39ms, total 39ms
12-21 00:31:07.606: D/dalvikvm(30222): GC_FOR_ALLOC freed 3600K, 63% free 18648K/49480K, paused 42ms, total 42ms
12-21 00:31:12.151: D/dalvikvm(30222): GC_FOR_ALLOC freed 3640K, 63% free 18652K/49480K, paused 48ms, total 48ms
12-21 00:31:17.757: D/dalvikvm(30222): GC_FOR_ALLOC freed 3627K, 63% free 18669K/49480K, paused 93ms, total 93ms
12-21 00:31:24.014: D/dalvikvm(30222): GC_FOR_ALLOC freed 3641K, 63% free 18679K/49480K, paused 46ms, total 46ms
12-21 00:31:30.090: D/dalvikvm(30222): GC_FOR_ALLOC freed 3644K, 63% free 18688K/49480K, paused 48ms, total 48ms
12-21 00:31:35.536: D/dalvikvm(30222): GC_FOR_ALLOC freed 3639K, 63% free 18706K/49480K, paused 50ms, total 50ms
12-21 00:31:41.763: D/dalvikvm(30222): GC_FOR_ALLOC freed 3659K, 63% free 18711K/49480K, paused 52ms, total 53ms
12-21 00:31:47.439: D/dalvikvm(30222): GC_FOR_ALLOC freed 3652K, 63% free 18724K/49480K, paused 54ms, total 54ms
12-21 00:31:53.085: D/dalvikvm(30222): GC_FOR_ALLOC freed 3677K, 63% free 18716K/49480K, paused 38ms, total 38ms
12-21 00:31:59.882: D/dalvikvm(30222): GC_FOR_ALLOC freed 3672K, 63% free 18711K/49480K, paused 50ms, total 67ms
12-21 00:32:05.838: D/dalvikvm(30222): GC_FOR_ALLOC freed 3672K, 63% free 18704K/49480K, paused 42ms, total 42ms
12-21 00:32:13.276: D/dalvikvm(30222): GC_FOR_ALLOC freed 3680K, 63% free 18686K/49480K, paused 37ms, total 37ms
P.S。代码很长,因此我无法发布。
感谢您提供任何帮助,提示或猜测。
答案 0 :(得分:1)
为什么GC_FOR_ALLOC会被触发?有大量的空闲记忆。
引用myself:
JVM有一件事就是Dalvik VM没有:压缩垃圾收集器。当我们用支持垃圾收集的运行时运行的语言编写程序时,我们创建了一堆对象,然后我们发布了这些对象的一些子集。我们坚持了一段时间,因为我们仍在使用它们。例如,在Android中,我们的
Application
,我们的ContentProviders
,我们的Threads
,我们自己的静态数据成员等等将会存在很长一段时间,在许多情况下过程的持续时间。他们可以达到的任何东西也不会被垃圾收集。因此,我们分配了一堆内存并在我们的应用程序运行时释放了一些内存。使用压缩垃圾收集器,长期存在的对象在内存中滑动,以允许释放释放的内存块进行合并。网络是所有可用堆空间应该作为一个连续块可用,有资格进行分配。
(细节比这更复杂,但这是一篇博文,而不是论文)
使用非压缩垃圾收集器,内存中没有任何东西滑动。我们结束了堆碎片,因为曾经是一个原始的16MB(或32MB,或48MB,或其他)堆现在是一堆具有散布空闲内存的对象。即使我们可能有10MB的可用堆空间,如果该空闲堆空间的最大单块只有1MB,我们也无法分配8MB位图,因为没有足够大的空闲块。
Dalvik VM有一个非压缩的垃圾收集器。
您的GC_FOR_ALLOC
行表示您正在进行分配,在分配时没有任何空闲的连续大块,迫使Dalvik必须通过GC尝试释放内存,以便你结束了一个足够大的块。
如果您想减少或删除GC_FOR_ALLOC
行,则需要尝试确定您的大量分配。这里,“大”是指个别分配,因此高度复杂的对象图可能总体上“大”,但每个单独的对象都很小,因此不是问题。 byte[]
分配往往是罪魁祸首,至少对于位图争论应用而言。