标签: finalize

为什么传统的Dispose模式抑制最终化?

假设这是传统的Dispose模式(取自devx,但在许多网站上看到)

class Test : IDisposable
{
  private bool isDisposed = false;

  ~Test()
  {
    Dispose(false);
  }

  protected void Dispose(bool disposing)
  {
    if (disposing)
    {
      // Code to dispose the managed resources of the class
    }

    // Code to dispose the un-managed resources of the class

    isDisposed = true;
  }

  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
}
Run Code Online (Sandbox Code Playgroud)

我不明白为什么打电话GC.SupressFinalize(this).这需要我编写自己的托管资源处理,包括清空我的引用?我必须承认,我有点迷茫.有人会对这种模式有所了解吗?

理想情况下,我只想处理我的非托管资源,让GC自己进行托管收集.

实际上,我甚至不知道为什么我们指定一个终结器.在任何情况下,编码人员都应该自己处理,现在不应该他?如果这只是一个后备机制,我会删除它.

c# dispose finalize

9
推荐指数
1
解决办法
4606
查看次数

为什么引用不会在finalize方法覆盖时放入引用队列

public class Test {
    public static void main(String[] args) throws Exception {
        A aObject = new A();

        ReferenceQueue<A> queue = new ReferenceQueue<>();
        PhantomReference<A> weak = new PhantomReference<>(aObject, queue);

        aObject = null;
        System.gc();

        TimeUnit.SECONDS.sleep(1);

        System.out.println(queue.poll());
    }
}

class A{
    @Override
    protected void finalize() throws Throwable {
        // TODO Auto-generated method stub
        super.finalize();

        System.out.println("finalize");
    }
}
Run Code Online (Sandbox Code Playgroud)

结果是:

finalize
null
Run Code Online (Sandbox Code Playgroud)

但如果我删除A类中的finalize方法,结果是:

java.lang.ref.PhantomReference@5b2c9e5d
Run Code Online (Sandbox Code Playgroud)

所以,结果显示当我覆盖finalize方法时,弱对象没有被放入引用队列,那是因为aObject复活了吗?但我在finalize方法中没有做任何事情

java reference finalize

9
推荐指数
1
解决办法
120
查看次数

幻影参考对象

幻影参考用于验尸操作.Java规范规定,在清除幻像引用本身之前,不会释放幻像引用的对象.

我的问题是:此功能(对象未解除分配)的用途是什么?

(我提出的唯一想法是允许本机代码对对象进行事后清理,但这并不是很有说服力).

java phantom-reference finalize

8
推荐指数
1
解决办法
2066
查看次数

优雅地完成SoftReference指示

我正在使用一个搜索库,建议保持搜索句柄对象打开,这样可以使查询缓存受益.随着时间的推移,我发现缓存容易变得臃肿(几百兆并且不断增长),并且OOM开始启动.没有办法强制执行此缓存的限制,也没有计划它可以使用多少内存.所以我增加了Xmx限制,但这只是问题的临时解决方案.

最后,我想使这个对象所指java.lang.ref.SoftReference.因此,如果系统在可用内存上运行不足,它将让对象运行并根据需要创建一个新对象.这会在新开始后降低一些速度,但这比击中OOM要好得多.

我看到的关于SoftReferences的唯一问题是没有干净的方式让他们的指示物最终确定.在我的情况下,在销毁搜索句柄之前我需要关闭它,否则系统可能会用完文件描述符.显然,我可以将这个句柄包装到另一个对象中,在其上写一个终结器(或挂钩到ReferenceQueue/PhantomReference)然后松开.但是,嘿,这个星球上的每篇文章都建议不要使用终结器,特别是 - 针对释放文件句柄的终结器(例如Effective Java ed.II,第27页).

所以我有些困惑.我应该小心地忽略所有这些建议并继续.否则,还有其他可行的替代方案吗?提前致谢.

编辑#1:根据Tom Hawtin的建议测试了一些代码后添加了下面的文字.对我来说,似乎任何一个建议都没有用,或者我错过了一些东西.这是代码:

class Bloat {  // just a heap filler really
   private double a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;

   private final int ii;

   public Bloat(final int ii) {
      this.ii = ii;
   }
}

// as recommended by Tom Hawtin
class MyReference<T> extends SoftReference<T> {
   private final T hardRef;

   MyReference(T referent, ReferenceQueue<? super T> q) {
      super(referent, q);
      this.hardRef = referent;
   }
}

//...meanwhile, somewhere in the neighbouring galaxy...
{
   ReferenceQueue<Bloat> …
Run Code Online (Sandbox Code Playgroud)

java finalize finalizer soft-references

8
推荐指数
2
解决办法
2583
查看次数

使用dispose/finalize模式释放套接字/事件/ ummaged代码的正确技术

当我的类包含套接字和事件时,如何实现Dispose模式?

它应该是这样的吗?

class MyClass
{
   Socket m_ListenerSocket = new Socket();
   book m_Disposed=false;

   public void Dispose()
   {
      Dispose(true);
      GC.SuppressFinalize(this);
   }

   private void Dispose(bool isDisposing)
   {
      if (!m_Disposed)
      {
          if (isDisposing)
          {
              if (m_ListenerSocket != null)
              {
                   m_ListenerSocket.Dispose();
                   innerClass.Notify -= Notify;
              }
          }
        //finalized unmanged code here
        m_Disposed = true;
      }
  }

  ~MyClass()
  {
       Dispose(false);
  }
}
Run Code Online (Sandbox Code Playgroud)

我很困惑...套接字类是"托管代码c#版本的winSock"?因此,如果用户名为dispose("isDisposing IS为true"),它应该被释放,那么事件处理程序呢?

所以在最终评论部分应该只释放Inptr对象?谢谢.

c# sockets dispose unmanaged finalize

8
推荐指数
1
解决办法
2261
查看次数

为什么Java中的一些资源没有被垃圾收集,必须关闭或自动关闭?

如果你是幸运一些类实现AutoClosable但有时你必须要小心,检查现有的方法要注意有一个close,destroyshutdown方法(或什么都笔者决定将它命名).

这是Java中资源泄漏的主要来源.

我和一位同事正在讨论这个问题,并且也想知道:为什么这不能以某种方式自动化?

从理论上讲,您可以使用finalize这种情况,但不建议这样做.那么为什么没有办法只使用其中一些可关闭的资源并让GC在实例不再可用时自动关闭它们而不必记住明确地写一些close处理代码(比如try ...)?

这是因为在GC启动之前系统可能资源不足(文件描述符,...)?

注意:我尽可能使用autoclose并使用FindBugs(+ FB contrib)检查我的代码是否存在内存泄漏,但我仍然想知道......

同样感兴趣(如答案中所讨论的):最终确定的弃用.

java resources garbage-collection finalize

8
推荐指数
1
解决办法
174
查看次数

对象没有最终确定,Finalizer线程没有做任何事情

在我们的服务器上,我们开始遇到问题OutOfMemoryError.我们使用Eclipse Memory Analysis分析了堆转储,并发现许多对象都要进行最终化(约占堆的2/3):

在此输入图像描述

我们发现,它可能是一些finalize()方法阻塞.我发现了几个关于这个问题的bug报告(这里这里),它总是在Finalizer线程堆栈中表现出来,它在某个地方被阻塞了.但在我们的例子中,这个帖子是WAITING:

"Finalizer" daemon prio=10 tid=0x43e1e000 nid=0x3ff in Object.wait() [0x43dfe000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x4fe053e8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133)
        - locked <0x4fe053e8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:189)
Run Code Online (Sandbox Code Playgroud)

编辑:

然后我们尝试添加-XX:+UseConcMarkSweepGC,但没有成功,只有OutOfMemoryErrors 的频率减少,所以我们首先认为它有所帮助.

最后,我们怀疑JVM错误并从OpenJDK 1.6.0_30升级到Oracle JDK 1.7.0_51,问题消失了(至少看起来如此,在过去4小时内使用的堆没有增长).我们不记得finalize方法有任何变化,我们也没有升级任何库,在那段时间里只有很小的发展.问题不会在我们的测试服务器上重现,具有相同的配置,除了它是64位JVM而生产服务器是32位.

问题是:什么可能是对象没有最终确定和Finalizer线程等待下一个对象的原因?我们是否正确分析了堆转储?

谢谢你的所有答案.

java garbage-collection finalize out-of-memory

7
推荐指数
1
解决办法
2735
查看次数

如何在Java中标记为最终化的对象(以便第二次不调用finalize方法)?

主要问题在于主题,但是让我展示我对Java中最终化过程的看法,以便我可以向您提出更多要求.

那么gc通过标记所有活动对象来启动垃圾收集.当所有可到达的对象都标记为"实时"时.所有其他对象都无法访问.下一步是检查每个无法到达的对象,并确定它是否可以立即进行清理,或者应该首先完成.如果对象的finalize方法有一个主体,那么gc会想到下一个方法,那么这个对象是可以最终确定的并且应该最终确定; 如果对象的finalize方法有一个空体(protected void finalize(){})那么它不能最终化并且现在可以被gc清理.(我是对的吗?)
所有可终结的对象将放在同一个队列中,以便稍后逐一完成.据我所知,可终结的对象可以花费大量时间放在队列中,同时等待轮到他们完成.这可能发生,因为通常只有一个名为Finalizer的线程从队列中获取对象并调用它们的finalize方法,当我们在某个对象的finalize方法中有一些耗时的操作时,队列中的其他对象将等待很长时间才能完成.好的,当一个对象完成后,它被标记为FINALIZED并从队列中删除.在下一个垃圾收集过程中,收集器将看到此对象无法访问(再次)并且具有非空的finalize方法(再次),因此该对象应该被放入队列中(再次) - 但它不会因为收集器以某种方式看到这个对象被标记为FINALIZED.(这是我的主要问题:这个对象被标记为FINALIZED的方式,收集器如何知道该对象不应该再次终结?)

java garbage-collection finalize finalization finalizer

6
推荐指数
1
解决办法
1246
查看次数

是否需要java的finalize方法?

我读过的关于java finalize方法的所有内容都说不要使用它.它似乎几乎永远不会被保证被调用,即使它存在也可能出现问题.

还有一些其他问题要求何时使用它,似乎普遍的共识绝不是.

我自己从未使用它(主要是因为没有警告),我没有看到它在任何地方使用过.

是否有任何合适的案例?有没有其他选择的情况?

如果没有,为什么会在那里?是否有内部类使用它并要求方法可用?或者它只是不应该存在的东西?

我对使用它的时间并不是那么感兴趣(已经用"从不"回答),但澄清为什么它甚至给出了"从不"的回答.如果它是如此无用和危险,为什么它没有被折旧和删除?

java finalize

6
推荐指数
1
解决办法
235
查看次数

如何使用PhantomReference作为finalize()替换

适用于PhantomReference的 Javadoc 8 指出:

与Java终结机制相比,虚拟引用最常用于以更灵活的方式调度事前清理操作。

因此,我尝试创建一个线程,该线程正在调用close()符合垃圾回收条件的Test Object方法。在run()试图获得所有测试对象的预验

实际上,检索到的测试对象都是null。预期的行为是检索测试对象并调用该close方法。

无论创建多少个测试对象,都不会在验尸前捕获单个测试对象(您必须增加超时并多次调用GC)。

我究竟做错了什么?这是Java错误吗?

可运行的测试代码:

我试图创建一个最小,完整和可验证的示例,但是它仍然很长。我java version "1.8.0_121"在Windows 7 64位上使用32位。

public class TestPhantomReference {

    public static void main(String[] args) throws InterruptedException {
        // Create AutoClose Thread and start it
        AutoCloseThread thread = new AutoCloseThread();
        thread.start();

        // Add 10 Test Objects to the AutoClose Thread
        // Test Objects are directly eligible for GC
        for (int i …
Run Code Online (Sandbox Code Playgroud)

java garbage-collection phantom-reference finalize finalizer

6
推荐指数
2
解决办法
1157
查看次数