是否有可能在Java中强制垃圾收集,即使这很棘手?我知道System.gc();和Runtime.gc ();但他们只建议做GC。如何强制GC?


当前回答

我们可以使用java运行时触发jmap -histo:live <pid>。这将强制在堆上进行完整的GC,以标记所有活动对象。

public static void triggerFullGC() throws IOException, InterruptedException {
    String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
    Process process = Runtime.getRuntime().exec(
            String.format("jmap -histo:live %s", pid)
    );
    System.out.println("Process completed with exit code :" + process.waitFor());
}

其他回答

在OutOfMemoryError的文档中,它声明除非虚拟机在完整的垃圾回收后未能回收内存,否则它不会被抛出。因此,如果您一直分配内存直到出现错误,那么您将已经强制进行完整的垃圾收集。

想必您真正想问的问题是“如何回收我认为应该通过垃圾收集回收的内存?”

FYI

方法调用System.runFinalizersOnExit(true)保证终结器方法 在Java关闭之前调用。然而,这种方法本质上是不安全的 并且已经被弃用。另一种方法是在方法中添加“关机钩子” Runtime.addShutdownHook。

马萨拉特·西迪基

我们可以使用java运行时触发jmap -histo:live <pid>。这将强制在堆上进行完整的GC,以标记所有活动对象。

public static void triggerFullGC() throws IOException, InterruptedException {
    String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
    Process process = Runtime.getRuntime().exec(
            String.format("jmap -histo:live %s", pid)
    );
    System.out.println("Process completed with exit code :" + process.waitFor());
}

如果需要强制垃圾收集,也许应该考虑如何管理资源。您正在创建持久化在内存中的大对象吗?您是否正在创建具有Disposable接口的大型对象(例如图形类),并且在使用它时不调用dispose() ?您是否在类级别声明了只需要在单个方法中使用的东西?

在未来的版本中,.gc可能会被淘汰——一位Sun工程师曾经评论说,世界上可能只有不到20人真正知道如何使用.gc()——我昨晚花了几个小时研究一个中心/关键数据结构,使用securerrandom生成的数据,当超过40000个对象时,虚拟机就会变慢,就像指针用光了一样。显然,它被16位指针表所阻塞,并表现出典型的“机械故障”行为。

我尝试了-Xms等等,一直在旋转,直到它运行到大约57,xxx什么的。然后,在gc()之后,它将运行gc,从57,127到57,128——大约是Easy Money营地代码膨胀的速度。

你的设计需要基本的重新工作,可能是一个滑动窗口的方法。