【问题标题】:How can I tell who calls System.gc()?我如何知道谁调用了 System.gc()?
【发布时间】:2011-07-29 08:57:05
【问题描述】:

在一个正在运行的系统中,我们看到很多“Full GC (System)”,这表明有人触发了 System.gc()。

有没有办法找出代码中发生这种情况的地方?

我确实搜索了所有可用的来源,但没有发现任何可疑的东西,所以它一定在某个地方,可能是在同一个容器或容器本身中运行的另一个应用程序。

【问题讨论】:

标签: java logging garbage-collection stack-trace


【解决方案1】:

您可以更改 Runtime 类以记录 gc() 被调用到文件的位置(System.gc() 调用 Runtime.gc())

为此,编辑一个副本,编译它并将其添加到您的-Xbootclasspath/p:

然而,大量的 Full GC 更有可能是由于幸存者空间不足或完整的终身空间。

你可以试试跑步吗

jstat -gccause {pid} 5s 

【讨论】:

  • 据我所知,您不能真正更改 Runtime 类,因为 gc() 是本机方法。您可以更改 System.gc(),但这不是唯一可以调用 Runtime.getRuntime().gc() 的地方 - 一个示例是 sun.management.MemoryImpl。当然图书馆也可以这样称呼它,所以登录系统可能不会告诉你一切。
【解决方案2】:

您使用的某些库可能会调用显式 gc。您可以使用-XX:-DisableExplicitGC 禁用它,并查看它是否在日志中停止Full GC

【讨论】:

  • 好点;这样,我可以快速区分显式 GC 调用和“内存不足”调用。
【解决方案3】:

使用以下大括号脚本和 jvisualvmbtrace 插件 将轻松显示System.gc 的调用者。

// import all BTrace annotations
import com.sun.btrace.annotations.*;

// import statics from BTraceUtils class
import static com.sun.btrace.BTraceUtils.*;

// @BTrace annotation tells that this is a BTrace program
@BTrace
public class GCcaller {
    // @OnMethod annotation tells where to probe.
    // In this example, we are interested in entry
    // into the Thread.start() method.
    @OnMethod(
        clazz="java.lang.System",
        method="gc"
    )
    public static void func() {
        // println is defined in BTraceUtils
        // you can only call the static methods of BTraceUtils
        println("about to start a System.gc!");
        jstack();
    }
}

【讨论】:

    【解决方案4】:

    在 Java 中,您不能“调用”垃圾收集器。如果您在调用 System.gc() 方法时看到 documentation,则 vm 只是作为建议运行垃圾收集器,但不能保证有效调用。是一个内部进程,即使您在堆栈中需要空间时不调用也会自动调用。

    如果您看到大量 Full GC,则可能是应用程序未正确释放资源的症状。你应该监控堆看看有什么问题

    【讨论】:

    • +1 好点。在我的例子中,使用了一个工具来分析问题,它说“449 个集合中有 17 个 (3,786%) 是由 System.gc() 调用触发的。”
    猜你喜欢
    • 2020-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多