分享

浅谈Java的System.gc()实现...

 昵称74191256 2021-03-15

我们都知道System.gc()用于调用垃圾收集器。很久之前我一直认为执行System.gc()之后,虚拟机会立刻垃圾回收。

抱歉,我理解错了。


直到看完System.gc()的源码之后才搞清楚,执行System.gc()函数的作用只是提醒或告诉虚拟机,希望进行一次垃圾回收。
至于什么时候进行回收还是取决于虚拟机,而且也不能保证一定进行回收(如果-XX:+DisableExplicitGC设置成true,则不会进行回收)。

然后在简单说一下什么样的对象会被gc()回收:sum的hotspot虚拟机是通过可达性分析算法来判断对象是否需要回收。这里不重点讲述可达性分析算法,之后在单独写一篇博客来介绍。

先来简单看一下System.gc()的源码吧:

  1. /**
  2. * Runs the garbage collector.
  3. * <p>
  4. * Calling the <code>gc</code> method suggests that the Java Virtual
  5. * Machine expend effort toward recycling unused objects in order to
  6. * make the memory they currently occupy available for quick reuse.
  7. * When control returns from the method call, the Java Virtual
  8. * Machine has made a best effort to reclaim space from all discarded
  9. * objects.
  10. * <p>
  11. * The call <code>System.gc()</code> is effectively equivalent to the
  12. * call:
  13. * <blockquote><pre>
  14. * Runtime.getRuntime().gc()
  15. * </pre></blockquote>
  16. *
  17. * @see java.lang.Runtime#gc()
  18. */
  19. public static void gc() {
  20. Runtime.getRuntime().gc();
  21. }

简单看一下gc()函数的注释(翻译的不对的地方望见谅,水平有限)
Runs the garbage collector.

Calling the <code>gc</code> method suggests that the Java Virtual
Machine expend effort toward recycling unused objects in order to
make the memory they currently occupy available for quick reuse.
When control returns from the method call, the Java Virtual
Machine has made a best effort to reclaim space from all discarded
objects.

运行垃圾收集器。

调用gc()函数表明Java虚拟机花费了很多精力来回收未使用的对象,以使它们当前占用的内存可用于快速重用。
当控制从方法调用返回时,Java虚拟机已尽最大努力从所有丢弃的对象中回收空间。

在注释中也明确的说明了,调用System.gc()等同于调用Runtime.getRuntime().gc()。

好吧,我们接着来分析Runtime.getRuntime().gc():

  1. /**
  2. * Runs the garbage collector.
  3. * Calling this method suggests that the Java virtual machine expend
  4. * effort toward recycling unused objects in order to make the memory
  5. * they currently occupy available for quick reuse. When control
  6. * returns from the method call, the virtual machine has made
  7. * its best effort to recycle all discarded objects.
  8. * <p>
  9. * The name <code>gc</code> stands for "garbage
  10. * collector". The virtual machine performs this recycling
  11. * process automatically as needed, in a separate thread, even if the
  12. * <code>gc</code> method is not invoked explicitly.
  13. * <p>
  14. * The method {@link System#gc()} is the conventional and convenient
  15. * means of invoking this method.
  16. */
  17. public native void gc();

好吧,原来gc()是native方法,在java层面只能看到这么多了,先来看一下注释的意思吧。

意思和System.gc()的注释差不多,需要注意的是,在注解中也说明了,需要在单独的线程自动执行。

正好我电脑上有OpenJDK8的代码,我们接着去Hotspot里看看System.gc()是怎么实现的吧

先下载OpenJDK的源码,我下载的是OpenJDK8的源码,在jdk/src/share/native/java/lang 目录中有一个 Runtime.c 文件

  1. JNIEXPORT void JNICALL
  2. Java_java_lang_Runtime_gc(JNIEnv *env, jobject this)
  3. {
  4. JVM_GC();
  5. }

没错就是这个函数(抱歉,我不能解释我是怎么知道就是这个函数的,因为我是根据名称推测的。。。),很简单,只是调用了JVM_GC这个函数。

那我们接着看JVM_GC这个函数实现的逻辑吧,其实我不用C和C++,也是咨询了JVM大神才定位到JVM_GC函数的定义的。

在hotspot/src/share/vm/prims 目录中有一个 jvm.cpp 文件

  1. JVM_ENTRY_NO_ENV(void, JVM_GC(void))
  2. JVMWrapper("JVM_GC");
  3. if (!DisableExplicitGC) {
  4. Universe::heap()->collect(GCCause::_java_lang_system_gc);
  5. }
  6. JVM_END

其实我不是太能看懂,我只能带着我的疑问一步步来推测了,DisableExplicitGC 是在哪定义的呢?默认是true还是false呢?

来跟大家说一下怎么找到 DisableExplicitGC 这个函数的定义:在OpenJDK目录下执行 grep -nr "DisableExplicitGC" . 。唉,因为不会,所以只能用这么笨的办法了,见笑。

在hotspot/src/share/vm/runtime 目录中有一个 globals.hpp 文件,这里面就有 DisableExplicitGC 的定义

  1. product(bool, DisableExplicitGC, false,
  2. "Ignore calls to System.gc()")

好了,这个疑问解决了,默认设置成了false,所以在不修改 DisableExplicitGC的情况下,会执行 if 里面的代码的。接着分析 if 里面的代码啦。

调用了collect()函数,所以我们看一下这个函数的实现:

  1. void GenCollectedHeap::collect(GCCause::Cause cause) {
  2. if (should_do_concurrent_full_gc(cause)) {
  3. #if INCLUDE_ALL_GCS
  4. // mostly concurrent full collection
  5. collect_mostly_concurrent(cause);
  6. #else // INCLUDE_ALL_GCS
  7. ShouldNotReachHere();
  8. #endif // INCLUDE_ALL_GCS
  9. } else if (cause == GCCause::_wb_young_gc) {
  10. // minor collection for WhiteBox API
  11. collect(cause, 0);
  12. } else {
  13. #ifdef ASSERT
  14. if (cause == GCCause::_scavenge_alot) {
  15. // minor collection only
  16. collect(cause, 0);
  17. } else {
  18. // Stop-the-world full collection
  19. collect(cause, n_gens() - 1);
  20. }
  21. #else
  22. // Stop-the-world full collection
  23. collect(cause, n_gens() - 1);
  24. #endif
  25. }
  26. }
  1. bool GenCollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) {
  2. return UseConcMarkSweepGC &&
  3. ((cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) ||
  4. (cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent));
  5. }

如果should_do_concurrent_full_gc返回true,那会执行collect_mostly_concurrent做并行的回收,should_do_concurrent_full_gc的实现也就不在多说了,代码贴出来了。有兴趣的朋友可以继续跟踪下去。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多