是否有可能在Java中强制垃圾收集,即使这很棘手?我知道System.gc();和Runtime.gc ();但他们只建议做GC。如何强制GC?
当前回答
是的,几乎可以强迫你必须以相同的顺序调用方法,同时这些方法是:
System.gc ();
System.runFinalization ();
即使只是一个对象来清理,同时使用这两个方法强制垃圾收集器使用不可达对象的finalize()方法释放分配的内存并执行finalize()方法的状态。
不过是一个可怕的实践使用垃圾收集器,因为使用它可能会引入一个加载的软件可能甚至比在内存坏,垃圾收集器有自己的线程是不可能控制+根据gc可能需要更多的时间和所使用的算法是考虑非常低效,您应该检查您的软件如果它坏在gc的帮助,因为它绝对是坏,一个好的解决方案不能依赖于gc。
注意:只是要记住,只有在finalize方法中没有对对象进行重赋时,这才会起作用,如果发生这种情况,对象将保持存活,它将有一个复活,这在技术上是可能的。
其他回答
我想在这里补充一些东西。请不要说Java运行在虚拟机而不是实际的机器上。虚拟机有自己的与机器通信的方式。它可能因系统而异。现在,当我们调用GC时,我们要求Java虚拟机调用垃圾收集器。
由于垃圾收集器是与虚拟机一起使用的,我们不能强迫它当场进行清理。相反,我们将请求与垃圾收集器一起排队。这取决于虚拟机,在特定时间之后(这可能因系统而异,通常在分配给JVM的阈值内存已满时),实际机器将释放空间。: D
如果需要强制垃圾收集,也许应该考虑如何管理资源。您正在创建持久化在内存中的大对象吗?您是否正在创建具有Disposable接口的大型对象(例如图形类),并且在使用它时不调用dispose() ?您是否在类级别声明了只需要在单个方法中使用的东西?
我们可以使用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());
}
您可以从命令行触发GC。这对于batch/crontab非常有用:
jdk1.7.0/bin/jcmd <pid> GC.run
看到的:
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr006.html
I did some experimentation (see https://github.com/mikenakis/ForcingTheJvmToGarbageCollect) trying about a dozen different ways of performing a garbage collection, including ways described in this answer, and more, and I found that there is absolutely no frigging way to deterministically force the JVM to do a complete garbage collection. Even the best answers to this question are only partially successful in that the best they achieve is some garbage collection, but never a guaranteed full garbage collection.
我的实验表明,下面的代码片段产生了最好的(最不坏的)结果:
public static void ForceGarbageCollection()
{
long freeMemory = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed();
for( ; ; )
{
Runtime.getRuntime().gc();
Runtime.getRuntime().runFinalization();
long newFreeMemory = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed();
if( newFreeMemory == freeMemory )
break;
freeMemory = newFreeMemory;
sleep( 10 );
}
}
其中sleep()函数如下:
private static void sleep( int milliseconds )
{
try
{
Thread.sleep( milliseconds );
}
catch( InterruptedException e )
{
throw new RuntimeException( e );
}
}
不幸的是,睡眠中的数字10是有魔力的;它假设您每秒执行中等数量的内存分配,这将导致中等数量的结束。如果你通过对象的速度更快,那么10可能是不够的,你可能需要等待更长的时间。您可以将其设置为100,但无论您将其设置为多少,总有可能它不够用。
话虽如此,在一个受控制的环境中,10个就足够了,这种方法被观察到可以持续地从内存中消除所有不可访问的对象,而本问答中提到的其他方法都不能做到这一点。我在github上链接的实验代码证明了这一点。
在我看来,Java虚拟机没有提供执行强制的、无条件的、确定的、绝对彻底的、让世界停止的垃圾收集的方法,这一事实使它崩溃了。
换句话说,JVM的创造者是如此傲慢,以至于认为他们比我们更了解我们是否想要这样做,或者我们是否应该这样做。别那么傲慢。如果某些东西像魔法一样起作用,那么必须提供一些绕过魔法的方法。
推荐文章
- javac和Eclipse编译器之间的区别是什么?
- 工厂模式和策略模式之间的区别是什么?
- 在Java中使用正则表达式提取值
- 如何允许所有网络连接类型HTTP和HTTPS在Android(9)馅饼?
- Intellij IDEA Java类在保存时不能自动编译
- 何时使用Mockito.verify()?
- 在maven中安装mvn到底做什么
- 不可变与不可修改的集合
- 如何在JSON中使用杰克逊更改字段名
- GSON -日期格式
- 如何从线程捕获异常
- 无法解析主机"<URL here>"没有与主机名关联的地址
- 如何在Java中打印二叉树图?
- String.format()在Java中格式化双重格式
- com.jcraft.jsch.JSchException: UnknownHostKey