Android GC深度分析

        今天发现个有趣的现象, 点击DDMS Monitor的initiate gc按钮和调用System.gc的效果不同。 ”initiate gc“按钮的效果更明显, 即内存下降更多。 我在想这个”initiate gc“是怎么做到的???

      PS: 代码调用gc实际上是给虚拟机发个信号, 并不能立刻执行gc; 而Android Studio的这个按钮会马上执行gc! 所有在检查内存泄漏后要点击“initate gc”按钮, 该按钮能释放不可达对象。

         Android GC深度分析_第1张图片

 VS   在Activity的onDestory函数中显示触发gc。

    @Override
    protected void onDestroy() {
        super.onDestroy();

        Runtime.getRuntime().gc();
    }

      备注:Runtime.getRuntime.gc()和System.gc()可以理解为一个东西, 只是写法不同而已。

      从二者的日志开始分析, 使用小米4手机、MIUI8、Android6.0系统测试。 点击“Initiate gc"或执行System.gc都会显示下面2行日志。

12-06 14:53:35.624 I/art     ( 5967): Starting a blocking GC Explicit
12-06 14:53:35.664 I/art     ( 5967): Explicit concurrent mark sweep GC freed 3962(256KB) AllocSpace objects, 15(28MB) LOS objects, 40% free, 65MB/108MB, paused 440us total 39.442ms

     在Android源码中搜索"Starting a blocking", 最终确定“Starting a blocking GC Explicit"是在heap.cc里打印的。

Android GC深度分析_第2张图片

       这里的cause就是字符串Explicit, 在gc_cause.cc里定义。

Android GC深度分析_第3张图片

           gc_cause.cc定义了12种gc的理由。 我们使用的System.gc和Runtime.getRuntime.gc的枚举类型是kGcCauseExplicit。

// What caused the GC?
enum GcCause {
  // GC triggered by a failed allocation. Thread doing allocation is blocked waiting for GC before
  // retrying allocation.
  kGcCauseForAlloc,
  // A background GC trying to ensure there is free memory ahead of allocations.
  kGcCauseBackground,
  // An explicit System.gc() call.
  kGcCauseExplicit,
  // GC triggered for a native allocation.
  kGcCauseForNativeAlloc,
  // GC triggered for a collector transition.
  kGcCauseCollectorTransition,
  // Not a real GC cause, used when we disable moving GC (currently for GetPrimitiveArrayCritical).
  kGcCauseDisableMovingGc,
  // Not a real GC cause, used when we trim the heap.
  kGcCauseTrim,
  // Not a real GC cause, used to implement exclusion between GC and instrumentation.
  kGcCauseInstrumentation,
  // Not a real GC cause, used to add or remove app image spaces.
  kGcCauseAddRemoveAppImageSpace,
  // Not a real GC cause, used to implement exclusion between GC and debugger.
  kGcCauseDebugger,
  // GC triggered for background transition when both foreground and background collector are CMS.
  kGcCauseHomogeneousSpaceCompact,
  // Class linker cause, used to guard filling art methods with special values.
  kGcCauseClassLinker,
};

       System.gc和Runtime.getRuntime.gc最终调用的都是OpenJdkJvm.cc中的JVM_GC方法。 我推测ddms monitor的“initate gc”按钮会调用CollectGarbage(true)。

Android GC深度分析_第4张图片

       clear_soft_references为true或false时释放的内存空间会不同, 所以推测DDMS Monitor的“initiate gc”重写了native层添加了对应接口。

Android GC深度分析_第5张图片


补充: https://github.com/TencentOpen/GT/blob/master/android/src/com/tencent/wstt/gt/proInfo/floatView/GTMemHelperFloatview.java

         如果有root权限, 执行adb shell kill -10 pid也可以调用GC, 在linux kill命令中状态10表示SIGUSR1,调用的是signal_catcher.cc的HandleSigUrs1函数。

void SignalCatcher::HandleSigUsr1() {
  LOG(INFO) << "SIGUSR1 forcing GC (no HPROF)";
  Runtime::Current()->GetHeap()->CollectGarbage(false);
}





   

你可能感兴趣的:(Android)