如何在Java中强制垃圾收集?
是否有可能强制在Java中进行垃圾收集,即使这样做很棘手? 我知道System.gc();
和Runtime.gc();
但他们只build议做GC。 我如何强制GC?
你最好的select是调用System.gc()
,它只是一个提示给你想要做集合的垃圾收集器。 虽然垃圾收集器是非确定性的,但是没有办法强制和立即收集。
jlibs库有一个很好的垃圾收集工具类 。 你可以用WeakReference对象强制垃圾收集。
RuntimeUtil.gc()从jlibs:
/** * This method guarantees that garbage collection is * done unlike <code>{@link System#gc()}</code> */ public static void gc() { Object obj = new Object(); WeakReference ref = new WeakReference<Object>(obj); obj = null; while(ref.get() != null) { System.gc(); } }
最好的(如果不是唯一的)强制GC的方法是编写一个定制的JVM。 我相信垃圾收集器是可插拔的,所以你可能只是select其中一个可用的实现正在调整它。
注意:这不是简单的答案。
使用Java™虚拟机工具接口(JVM TI) ,该function
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
将“强制VM执行垃圾回收”。 JVM TI是JavaTM平台debugging器体系结构(JPDA)的一部分 。
是的 ,几乎可以强迫你必须以相同的顺序调用方法,同时这些方法是:
System.gc (); System.runFinalization ();
即使只是一个对象来清除这两个方法的使用,同时强制垃圾收集器使用释放已分配内存的无法访问的对象的finalise()
方法,并执行finalize()
方法的状态。
但是使用垃圾收集器是一种可怕的做法,因为使用垃圾收集器可能会给软件带来过载,甚至可能比内存还要糟糕,垃圾收集器有自己的线程,这是无法控制的。由gc使用的algorithm可能需要更多的时间,并且被认为是非常低效的,你应该在gc的帮助下检查你的软件是否是最坏的,因为它肯定是坏的,一个好的解决scheme不能取决于gc。
注意:只有在finalize方法不是重新分配对象的情况下,如果发生这种情况,对象将保持活动状态,它将会有一个技术上可能的复活。
在OutOfMemoryError的文档下面,声明它将不会被抛出,除非虚拟机在完整的垃圾回收之后无法回收内存。 所以如果你一直分配内存,直到出现错误,那么你已经强制完成垃圾回收了。
大概你真正想问的问题是“我怎么能回收我想我应该通过垃圾回收回收的内存?
要手动请求GC(而不是从System.gc()):
- 转至:JDK中的bin文件夹eg.-C:\ Program Files \ Java \ jdk1.6.0_31 \ bin
- 打开jconsole.exe
- 连接到所需的本地进程。
- 转到内存选项卡,然后单击执行GC。
.gc是未来版本中的一个候选人 – 一位Sun工程师曾经评论说,世界上只有不到二十个人真的知道如何使用.gc() – 我昨晚在中央/关键时刻做了几个小时的工作数据结构使用SecureRandom生成的数据,在刚刚超过40,000个对象的地方,虚拟机会减速,就好像指针已经用完一样。 很显然,它正在窒息在16位指针表上,展现了经典的“失败的机器”行为。
我尝试了-XMS等等,一直保持着混乱,直到它会跑到57,xxx。 然后它会运行gc,从57,127到57,128之后,gc() – 大约在Easy Money的代码膨胀的速度。
您的devise需要重新devise,可能是一个滑动窗口的方法。
JVM规范没有说什么特定的垃圾收集。 由于这个原因,供应商可以自由地以他们的方式实施GC。
所以这种模糊性会导致垃圾收集行为的不确定性。 您应该检查您的JVM详细信息以了解垃圾收集方法/algorithm。 也有自定义行为的选项。
如果你能描述你需要垃圾收集的原因,那会更好。 如果您正在使用SWT,则可以处理Image
和Font
等资源以释放内存。 例如:
Image img = new Image(Display.getDefault(), 16, 16); img.dispose();
还有一些工具可以确定未处理的资源。
如果你需要强制垃圾收集,也许你应该考虑如何pipe理资源。 你正在创build大的对象,坚持在内存中? 你是否创build了具有Disposable
接口的大对象(例如graphics类),而不是在完成它时调用dispose()
? 你是否只需要在一个单独的方法中声明一个类的级别?
对批处理/ crontab有用:
jdk1.7.0 / bin / jcmd GC.run
真的,我不明白你的意思。 但是要明确“无限的对象创build”,我的意思是在我的大系统中有一些代码创build处理内存的对象,而我实际上无法得到这段代码,只是手势!
这是正确的,只有手势。 你有几个海报已经给出的标准答案。 让我们一个接一个:
- 我实际上无法得到这段代码
正确的是,没有实际的jvm – 这只是一个规范,描述所需行为的一大堆计算机科学……我最近从本地代码中挖掘出初始化Java对象。 为了得到你想要的东西,唯一的办法就是做所谓的积极归零。 如果做错了,错误是如此糟糕,如果做错了,我们不得不把自己限制在问题的原始范围:
- 我的大系统中的一些代码会创build对象
这里的大多数海报会假设你说的是你正在使用一个界面,如果这样的话,我们将不得不看看你是一次递交整个对象还是一个项目。
如果您不再需要一个对象,则可以将null指定给对象,但如果出错,则会生成空指针exception。 我敢打赌,如果你使用NIO,你可以做更好的工作
任何时候,你或我或任何其他人都会得到:“ 我需要那个可怕的东西 ”,这几乎是所有人都在努力工作的普遍前兆……给我们写一个小样本代码,实际使用的代码,并告诉我们你的问题。
不要感到沮丧。 通常情况下,这个解决scheme是你的dba正在使用一个在某个地方购买的软件包,而原始devise并没有针对海量的数据结构进行调整。
这是非常普遍的。
如果您的内存不足,发生OutOfMemoryException
,则可以尝试使用java -Xms128m -Xmx512m
而不是java来启动程序,从而增加可用于java的堆空间量。 这将给你一个128Mb的初始堆大小和最大512Mb,这远远超过了标准的32Mb / 128Mb。
(对不起,因为我没有足够的声望点,我不能添加这个评论。)
我曾经在一家image processing公司采访了一个Java工作(尽pipe我没有任何Java经验)。
他们对我感兴趣的悲惨故事是他们的程序将为图像分配一个巨大的缓冲区。 有一次,他们完成了形象和记忆,他们会尊重它。 知道他们确实需要尽快恢复内存,他们试图在程序安静的时候使用Java gc()的显式调用。 不幸的是,gc()仅仅是对Java运行时的一个build议,并没有任何作用。
我记得,他们最终不得不自己回收记忆。
这是来自凯西塞拉利昂和伯特贝茨的书SCJP研究指南:
垃圾收集器在JVM的控制下。 JVM决定何时运行垃圾收集器。 从Java程序中,您可以让JVM运行垃圾收集器,但在任何情况下都不能保证JVM遵守。 如果放在自己的设备上,JVM通常会在检测到内存不足时运行垃圾收集器。 经验表明,当您的Java程序发出垃圾回收请求时,JVM通常会在短时间内批准您的请求,但是没有任何保证。 只要你认为你可以依靠它,JVM就会决定忽略你的请求。
FYI
方法调用System.runFinalizersOnExit(true)保证在Javaclosures之前调用终结器方法。 但是,这种方法本质上是不安全的,已被弃用。 另一种方法是使用Runtime.addShutdownHook方法添加“closures挂钩”。
Masarrat Siddiqui
最好的(如果不是唯一的)强制GC
方法是编写一个自定义的JVM
。 我相信Garbage collectors
是可插入的,所以你可能只是select其中一个可用的实现正在调整它。
有一些间接的方式来强制垃圾收集器。 你只需要填充临时对象的堆,直到垃圾收集器执行的时候。 我已经用这种方式强制垃圾收集器的类:
class GarbageCollectorManager { private static boolean collectionWasForced; private static int refCounter = 0; public GarbageCollectorManager() { refCounter++; } @Override protected void finalize() { try { collectionWasForced = true; refCounter--; super.finalize(); } catch (Throwable ex) { Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex); } } public int forceGarbageCollection() { final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000; int iterationsUntilCollected = 0; collectionWasForced = false; if (refCounter < 2) new GarbageCollectorManager(); while (!collectionWasForced) { iterationsUntilCollected++; int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC]; arr = null; } return iterationsUntilCollected; } }
用法:
GarbageCollectorManager manager = new GarbageCollectorManager(); int iterationsUntilGcExecuted = manager.forceGarbageCollection();
我不知道这个方法有多大用处,因为它不断填充堆,但是如果你有任务关键的应用程序必须强制GC – 当这可能是强制GC的Java便携式的方式。
我想在这里添加一些东西。 请不要说Java在虚拟机上运行,而不是真正的机器。 虚拟机与机器有自己的通信方式。 它可能会从系统到系统。 现在当我们调用GC时,我们要求Java的虚拟机调用垃圾收集器。
由于垃圾收集器是与虚拟机,我们不能强迫它在那里做清理。 相反,我们排队我们的请求与垃圾收集器。 这取决于虚拟机,在特定时间之后(这可能会随着系统的不同而改变,一般当分配给JVM的阈值内存已满时)实际的机器将释放空间。 :d
以下代码来自assertGC(…)方法。 它试图强制收集非确定性的垃圾收集器。
List<byte[]> alloc = new ArrayList<byte[]>(); int size = 100000; for (int i = 0; i < 50; i++) { if (ref.get() == null) { // Test succeeded! Week referenced object has been cleared by gc. return; } try { System.gc(); } catch (OutOfMemoryError error) { // OK } try { System.runFinalization(); } catch (OutOfMemoryError error) { // OK } // Approach the jvm maximal allocatable memory threshold try { // Allocates memory. alloc.add(new byte[size]); // The amount of allocated memory is increased for the next iteration. size = (int)(((double)size) * 1.3); } catch (OutOfMemoryError error) { // The amount of allocated memory is decreased for the next iteration. size = size / 2; } try { if (i % 3 == 0) Thread.sleep(321); } catch (InterruptedException t) { // ignore } } // Test failed! // Free resources required for testing alloc = null; // Try to find out who holds the reference. String str = null; try { str = findRefsFromRoot(ref.get(), rootsHint); } catch (Exception e) { throw new AssertionFailedErrorException(e); } catch (OutOfMemoryError err) { // OK } fail(text + ":\n" + str);
来源(为清晰起见,我添加了一些注释): NbTestCase示例