2013-09-26 39 views
3

在对谷歌代码中发现了一些图书馆中,我遇到了这个UTIL方法:Java:可靠地调用GC?

public static void gc(){ 
    Object obj = new Object(); 
    WeakReference ref = new WeakReference<Object>(obj); 
    obj = null; 
    while(ref.get()!=null) 
    System.gc(); 
} 

其医生说它提供了一种可靠的方法来调用GC,因为调用系统#GC()仅仅是没有任何保障的提示。我把它展示给了我的老大,他说我应该考虑为什么这种方法是无效的。 我读了一些关于弱引用的文章,但我仍然感到困惑。 有人可以告诉我这一点吗?

+11

专注于你的业务逻辑..其余的java处理! :) – Anirudha

+1

我绝对同意:)我永远不会依赖像“调用GC”的东西。我只是好奇。 – gyorgyabraham

+0

如果gc()只是一个提示,那么没有理由认为GC会实际发生。你在这里没有做什么真的让gc发生(想想GC的用途是什么...)?如果没有真正发生,你的方法会做什么? – Brabster

回答

7

我有直接的经验,你所发布的假设的“安全的GC”成语。

它不起作用。

原因很简单:只是清除弱ref的事实是而不是收集到对象的信号;它只意味着它通过任何强或软的参考变得无法达到。根据我的经验,这个信号在物体被回收之前到达。

一个更好的尝试是使用一个虚引用,这至少保证了对象已进入终结状态,但再次,它仍然可以占据堆,并在实践中它仍然占领它。另一种解释可能是,这个显然居住在伊甸园空间的特定对象确实得到了回收,但是GC的运行并不详尽,在其他几代人中还有更多的回忆。

在另一方面,我也非常可靠地使用这个简单的成语:

for (int i = 0; i < 3; i++) { System.gc(); Thread.sleep(500); } 

试一试,看看它是否适合你。 sleep部分是可选的:只有在System.gc()使用并发扫描时才需要。

如果你反对这种方法的明显浮躁,只要记住的任何方法显式GC-ing是变幻莫测的。这至少是诚实的,只是碰巧在实际的系统上工作。它自然不可移植,并且由于各种各样的原因,可能随时停止工作。即便如此,这是你获得的最好成绩。

+0

同意,我想知道对象在与GC代码相同的方法中声明时对“对象强度”的影响是什么。看起来像一个糟糕的计划,试图垃圾收集你刚刚宣布4线的对象。可能会更好地尽快将所有提及的内容都去掉。 –

+0

@grep在OP的代码中,对'obj'的引用确实被明确地清除了。 –

+0

弱refs只能由GC清除,这意味着只要GC变为空,GC就确实运行。问题在于你试图解决的问题“是否收集了物体”?与“GC是否至少运行一次?”不一样?终结者和所有的.. – Voo

2

重点是,那System.gc()不需要清理所有弱引用。并考虑一些Java虚拟机。如果System.gc为一次(第一次)确定为而不是清除该引用,则很可能在下次调用。因此,您有一个可能无限循环。可能取决于其他线程更改垃圾收集的状态以终止循环。

所以:一次就够了。

+0

根据我的经验,第二次电话几乎总是能够回收更多的记忆。可能是定稿周期。 –

+0

@MarkoTopolnik也有同样的体验(Oracle jvm)。虽然如果gc被实现为_“如果当前状态有足够的空间返回”,那么无界循环是愚蠢的。甚至Oracle的gc也有很多选择。所以两次做一个gc应该就足够了。实际上,创建一个触发垃圾回收的对象是不正当的。 –

+0

准确地说,我通常会使用两个电话,有时候只需要添加三分之一就可以达到很好的效果。我有时会打印'totalMemory - freeMemory'来确认第三个没有释放任何内存。 –

1

没有保证GC呼叫的方法,因为正如文档所述,System.gc只是系统可以忽略的提示。

因此,假设JVM忽略System.gc - 在这种情况下,整个事情只是循环,直到系统的其他部分导致GC。如果你运行单线程或者没有其他人分配太多的内存,你基本上在这里创建一个inifite循环。

0

问题是您的线程将停止并等待弱引用被清除,从而“模拟”垃圾回收。无法保证何时(甚至实际上)会发生这种情况。

您可能会长时间滞留在此while上等待。

+0

,如果我们把它放在一个线程? – Cruncher

+0

它阻止,你要么永远等待,要么手动杀死它。我以为这就是我刚才所说的? – blgt

0

我同意你应该专注于业务逻辑,但我觉得它是一个interssting实现,我认为它应该工作 - 理论上。

尽管如此,代码的问题在于,您在循环中等待收集的引用进行收集 - 一直忙于等待垃圾收集器移除对象,因为它只是weakly reachable

System.gc()只是一个提示。所以这个方法可能会永远等待。

目前我没有看到必要的用例。

为什么应用程序显式等待直到垃圾收集器运行?

0

编程我们需要确保,当一个obj被删除,那么它的相应条目应该被删除。只有这样,该对象才会成为垃圾收集的候选对象。否则,即使它在运行时没有被使用,这个陈旧的对象也不会被垃圾收集。

该引用引用的对象,如果该引用对象已被清除,则返回null。 作为WeakReference类的对象引用。所以它不会给null。但是在删除gc之后,它提供了null。

Object obj = new Object(); 
     WeakReference ref = new WeakReference<Object>(obj); 
     obj = null; 
     if(ref.get()!=null) 
     { 
      System.gc(); 
      System.out.println("remove ref"); 
     } 
     if(ref.get()!=null){ 
      System.out.println("not execute"); 
     } 

输出:

remove ref 

不要指定空值设置为obj。

Object obj = new Object(); 
     WeakReference ref = new WeakReference<Object>(obj); 
     if(ref.get()!=null) 
     { 
      System.gc(); 
      System.out.println("remove ref"); 
     } 
     if(ref.get()!=null){ 
      System.out.println("execute"); 
     } 

输出:

remove ref 
execute 
0

代码,试图迫使GC通常是一个潜在的更大的问题的迹象(即设计问题或对部分开发商缺少知识)。

我已经看到了一些使用情况,其中在生产代码中调用System.gc()实际上是有意义的,例如,在打印当前的内存使用情况之前 - 值是否关闭并不重要,但我们希望提高值尽可能小。当然,我们知道GC已启用 - 我们用它来自动检测QA系统上的内存泄漏。

一般来说,打电话System.gc()大叫“我的代码是越野车,我不知道如何解决它!”。