3

I'm writing an app that generates a fair amount of garbage but nowhere near enough to hit the memory limit. That is, even though garbage is generated, there is no need to collect garbage. However, in spite of this, and in spite of the fact that a very small percentage of the total memory available is being used, the garbage collector is constantly being called and lagging my application.

As you can see from this output, I'm using only 2% of my available memory and yet the garbage collector is constantly running:

12-22 04:36:08.219: D/dalvikvm(12033): WAIT_FOR_CONCURRENT_GC blocked 61ms
12-22 04:36:08.359: D/dalvikvm(12033): GC_CONCURRENT freed 1012K, 98% free 11865K/405196K, paused 4ms+13ms, total 73ms
12-22 04:36:08.359: D/dalvikvm(12033): WAIT_FOR_CONCURRENT_GC blocked 38ms
12-22 04:36:08.479: D/dalvikvm(12033): GC_CONCURRENT freed 1020K, 98% free 11862K/405196K, paused 3ms+13ms, total 66ms
12-22 04:36:08.479: D/dalvikvm(12033): WAIT_FOR_CONCURRENT_GC blocked 36ms
12-22 04:36:08.649: D/dalvikvm(12033): GC_CONCURRENT freed 1015K, 98% free 11863K/405196K, paused 2ms+16ms, total 78ms
12-22 04:36:08.649: D/dalvikvm(12033): WAIT_FOR_CONCURRENT_GC blocked 66ms
12-22 04:36:08.789: D/dalvikvm(12033): GC_CONCURRENT freed 1017K, 98% free 11861K/405196K, paused 2ms+13ms, total 66ms
12-22 04:36:08.789: D/dalvikvm(12033): WAIT_FOR_CONCURRENT_GC blocked 58ms

Avoiding this unnecessary garbage collection entirely will make or break my app.

Why is the garbage collector running if I have plenty of free memory? Is there any way I can keep the garbage collector from running until absolutely necessary? I should also mention I'm running on a rooted phone.

Thanks!

Edit: Ugh.. I've been trying to eliminate all garbage using factories and various techniques but there's still a fair amount being generated and I think it's due to some string concatenation of the form s1 + s2 + s3 . I've converted such expressions into forms where I can save references to each component but I'm not sure it's air-tight. Do you see any garbage being generated by the following lines?

String ss1 = input.substring(m, m+k1);
String ss2 = ss1 + possible_perturbations1.charAt(p1);
String ss3 = input.substring(m+k1+1, m+k2);
String ss4 = ss2 + ss3;
String ss5 = ss4 + possible_perturbations2.charAt(p2);
String ss6 = input.substring(m+k2+1, m+i+1);
String current_str = ss5 + ss6;

allStrs.add(ss1);
allStrs.add(ss2);
allStrs.add(ss3);
allStrs.add(ss4);
allStrs.add(ss5);
allStrs.add(ss6);
allStrs.add(current_str);

A couple notes: the remove functions of most of the standard library containers generate garbage, as do most binary operations between objects that generate temporary variables such as Strings, Integers, Doubles, etc... Obvious to most, I guess, but still good to make clear.

4

3 回答 3

3

如果没有您的代码,很难说为什么要调用垃圾收集器,这不是错误,而是 GC 有责任收集空闲的内存块。

当您拥有已创建但不再使用的对象时,垃圾收集器将激活。

不被 GC 滞后的最好方法是避免一直收集垃圾的需要。例如,您可以重用对象,而不是将它们归零并创建新对象。

但仅供参考,你不能阻止垃圾收集器运行,甚至不要尝试。

于 2012-12-22T09:55:05.820 回答
0

即使应用程序仅使用一小部分可用堆内存,它也会运行 Android 的 GC 是正常的。

一个可能的原因是:几毫秒长的 GC 运行优于几秒长的 GC 运行(用户会注意到这一点)。

你是如何制造垃圾的?在大多数情况下,您可以只创建固定数量的对象并重用它们(可能通过对象池)。

如果您 100% 确定自己知道自己在做什么并且不存在更好的解决方案,则可以保留对垃圾对象的引用以防止 GC 删除它们。但你几乎可以肯定不想这样做。

更新:

通常,您应该避免字符串连接(每个连接都会创建新对象)并使用 StringBuilder 代替:

String abc = a + b + c; // Wrong
String abc = new StringBuilder(a).append(b).append(c).toString(); // Right
于 2012-12-22T10:23:16.860 回答
0

垃圾收集器将随时运行。没有办法停止垃圾收集器。甚至没有真正的方法来调用垃圾收集器,你只问垃圾收集器是否想运行,但即使那样它也有可能不会运行。

垃圾收集器不仅会在内存不足时运行,它还会始终尝试防止“OutOfMemory”异常。据我所知,GC 将以给定的时间间隔运行,并查看范围内不再需要的变量。

正如 Sahil Mahajan Mj 已经说过的,最好的方法是重用你的对象。这不会阻止垃圾收集器运行(如前所述,它无论如何都会运行),但它会确保 GC 没有太多工作要做(这样可以节省时间)。

于 2012-12-22T10:26:58.997 回答