Android System.gc()注意点

简介:

背景

在看square Leakcanary源码时,发现这样一段话:

GcTrigger DEFAULT = new GcTrigger() {
    @Override public void runGc() {
      // Code taken from AOSP FinalizationTest:
      // https://android.googlesource.com/platform/libcore/+/master/support/src/test/java/libcore/
      // java/lang/ref/FinalizationTester.java
      // System.gc() does not garbage collect every time. Runtime.gc() is
      // more likely to perfom a gc.
      Runtime.getRuntime().gc();
      enqueueReferences();
      System.runFinalization(); 
}

跟进

到底有什么不一样呢?
我看了手头的4.2.2以及openjdk的源码:

public static void gc() {
        Runtime.getRuntime().gc();
}

System.gc()的实现就是调用Runtime.getRuntime().gc(),所以两者是等价的。所以这里是否是作者多虑了呢?我又看了一下5.0的源码,果然不一样了:


/**
 * Whether or not we need to do a GC before running the finalizers.
 */
  private static boolean runGC;

  /**
   * If we just ran finalization, we might want to do a GC to free the finalized objects.
   * This lets us do gc/runFinlization/gc sequences but prevents back to back System.gc().
   */
  private static boolean justRanFinalization;


/**
    * Provides a hint to the VM that it would be useful to attempt
    * to perform any outstanding object finalization.
    */
    public static void runFinalization() {
        boolean shouldRunGC;
        synchronized(lock) {
            shouldRunGC = runGC;
            runGC = false;
        }
        if (shouldRunGC) {
            Runtime.getRuntime().gc();
        }
        Runtime.getRuntime().runFinalization();
        synchronized(lock) {
            justRanFinalization = true;
        }
    }


 /**
   * Indicates to the VM that it would be a good time to run the
   * garbage collector. Note that this is a hint only. There is no guarantee
   * that the garbage collector will actually be run.
   */
  public static void gc() {
      boolean shouldRunGC;
      synchronized(lock) {
          shouldRunGC = justRanFinalization;
          if (shouldRunGC) {
              justRanFinalization = false;
        } else {
            runGC = true;
          }
    }
   if (shouldRunGC) {
          Runtime.getRuntime().gc();
   } 
}

这样改之后,单纯调用System.gc()是不会触发Runtime.getRuntime().gc()的。但是会把这次尝试纪录下来,等到下次调用System.runFinalization()时,会先执行这个Runtime.getRuntime().gc()。
这样改后的影响至少有两点:
1.单纯调用System.gc()是不会触发Runtime.getRuntime().gc()的,直到调用了System.runFinalization()
2.System.gc() -> System.gc() -> … -> System.gc() ->System.runFinalization(),最终只会调用一次Runtime.getRuntime().gc()

为什么要这样改呢?
找到了这个commit,是这样描述的:

Avoid running Runtime.gc() until we need to run finalization.

This prevents excessive explicit GC which are called from apps to get
good GC behavior on Dalvik. Calling System.gc() does not help on ART
since GC for alloc is much rarer.

If running finalizers is requested following a System.gc we remember
that a GC was requested and perform it ahead of finalization.

Bug: 12004934

从这里可以得到两点信息:
1.首先这是为了修复一个bug 12004934,具体什么bug找不到了
2.其次在art模式下,直接调用gc的效果不大。至于为什么,还没有深入进去了解,这是ART相关的另外一个专题了,后面再详细跟进。

回到开头,leakcanary的作者在这里直接用了Runtime.getRuntime().gc()的确是有理由的,但是这应该不是最好的方式,因为从这个提交的描述来看,连续调用Runtime.getRuntime().gc()可能存在bug。修改后的模式是gc / finalization / gc,虽然leakcanary这里的使用不会有问题。但是我觉得我们自己使用的话,用System.gc() 配合 System.runFinalization()会比较好。

目录
相关文章
|
存储 Java Android开发
[Android JNI] --- JNIEnv和JavaVM
[Android JNI] --- JNIEnv和JavaVM
218 0
|
缓存 Java Android开发
Android C++系列:JNI操作Bitmap
在 Android 通过 JNI 去调用 Bitmap,通过 CMake 去编 so 动态链接库的话,需要添加 jnigraphics 图像库。
415 0
|
Java Android开发
Android Runtime.getRuntime().freeMemory()会返回0吗?
### 背景 上周基于[LruCache](https://developer.android.com/reference/android/util/LruCache.html)实现了一个缓存,实现逻辑大概如下: ```java //使用剩余内存的1/16作为缓存池的最大值 int size = Runtime.getRuntime().freeMemory() / 16; Lru
2211 0
|
缓存 Java Android开发
|
Android开发
Android 使用 SoftReference 解决 Activity 存栈的内存泄漏问题
当 Android 想要退出应用时,我们总是希望完全退出。但是 Android 并没有提供一个完全退出 App 的函数。 Google 上搜索了一下,方法有很多,但是基本都是只退出了当前的 Activity, 并没有完全 finish 所有的 Activity。
1102 0
|
消息中间件 Java Android开发
android--线程
进程优先级 Foreground Process:前台进程,用户可见,被遮挡,虽然可见,但是不属于前台进程; Background Process:后台进程,用户不可见,进程包含service,重要性高,也存在空进程,不做任何事情。
823 0