- 浏览: 536315 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
飞天奔月:
public List<String> gener ...
实践中的重构30_不做油漆匠 -
在世界的中心呼喚愛:
<div class="quote_title ...
深入理解ReferenceQueue GC finalize Reference -
在世界的中心呼喚愛:
<div class="quote_title ...
深入理解ReferenceQueue GC finalize Reference -
在世界的中心呼喚愛:
<div class="quote_title ...
深入理解ReferenceQueue GC finalize Reference -
在世界的中心呼喚愛:
iteye比较少上,如果可以的话,可以发e-mail交流:ch ...
深入理解ReferenceQueue GC finalize Reference
关于对象如何销毁以及finalize更详细的信息
目录
概述
1 先看一个对象finalize的顺序问题。
2 对象再生及finalize只能执行一次
3 SoftReference WeakReference
4 PhantomReference
5 ReferenceQueue
Q&A
概述
先说一些基本的东西,GC只负责对象内存相关的清理,其他资源如文件句柄,db连接需要手动清理,以防止系统资源不足崩溃。System.gc()只是建议jvm执行GC,但是到底GC执行与否是由jvm决定的。
一个正常的对象的生命周期。
当新建一个对象时,会置位该对象的一个内部标识finalizable,当某一点GC检查到该对象不可达时,就把该对象放入finalize queue(F queue),GC会在对象销毁前执行finalize方法并且清空该对象的finalizable标识。
简而言之,一个简单的对象生命周期为,Unfinalized Finalizable Finalized Reclaimed。
Reference中引用的object叫做referent。
1 先看一个对象finalize的顺序问题。
按照http://java.sun.com/developer/technicalArticles/javase/finalization/
所说,对象a在finalize之前会保持b的引用,但是实验中对象a和a中的对象b的finalize方法运行时间有先有后,而且大部分时间里,a的finalize方法的执行时间是晚于b的finalize方法的。我记着java编程语言书中说是一切可以finalize的对象的finalize方法的执行顺序是不确定的。到底应该听谁的?最好的实践就是不要依赖finalize的顺序或者写一些防御代码。
【note】我仍然坚持最好的实践就是不要依赖finalize的顺序或者写一些防御代码。但是通过进一步的学习和实验,因为a有可能复活,所以在a没有决定到底复活不复活之前b是不会被回收的。控制台的顺序问题应该是多线程的问题导致的。
【note】查看了JLS后,确定了finalize是乱序执行的。
2 对象再生及finalize只能执行一次
对象b本来已经被置null,GC检查到后放入F queue,然后执行了finalize方法,但是执行finalize方法时该对象赋值给一个static变量,该对象又可达了,此之谓对象再生。
后来该static对象也被置null,然后GC,可以从结果看到finalize方法只运行了1次。为什么呢,因为第一次finalize运行过后,该对象的finalizable置为false了,所以该对象即使以后被gc运行,也不会执行finalize方法了。
很明显,对象再生是一个不好的编程实践,打乱了正常的对象生命周期。但是如果真的需要这么用的话,应该用当前对象为原型重新生成一个对象使用,这样以后这个新的对象还可以被GC运行finalize方法。
3 SoftReference WeakReference
SoftReference会尽量保持对referent的引用,直到JVM内存不够,才会回收SoftReference的referent。所以这个比较适合实现一些cache。
WeakReference不能阻止GC对referent的处理。
4 PhantomReference
幻影引用,幽灵引用,呵呵,名字挺好听的。
奇特的地方,任何时候调用get()都是返回null。那么它的用处呢,单独好像没有什么大的用处,所以要结合ReferenceQueue。
5 ReferenceQueue
ReferenceQueue WeakReference PhantomReference都有构造函数可以传入ReferenceQueue来监听GC对referent的处理。
分析,在GC运行时,检测到new A()生成的对象只有一个WeakReference引用着,所以决定回收它,首先clear WeakReference的referent,然后referent的状态为finalizable,同时或者一段时间后把WeakReference放入监听的ReferenceQueue中。
注意有时候最后的Assert.assertNotNull(obj);有时会失败,因为还没有来的及把WeakReference放入监听的ReferenceQueue中。
换成PhantomReference试试,
貌似和WeakReference没有什么区别呀,别急,还是有个细微的区别的,SoftReference和WeakReference在GC对referent状态改变时,先clear SoftReference/WeakReference对referent的引用,对应的referent状态为Finalizable,只是可以放入F queue,然后把SoftReference/WeakReference放入ReferenceQueue。
而PhantomReference当GC对referent的状态改变时,在把PhantomReference放入ReferenceQueue之前referent已经被GC处理到Reclaimed了,即该referent被销毁了。
搞了这么多,有什么用?可以使用PhantomReference更好的控制一些关于对象生命周期的事情,当WeakReference放入ReferenceQueue时,并不能保证该referent是被销毁了。别忘了对象可以在finalize方法里再生。而使用PhantomReference,当在ReferenceQueue中发现PhantomReference时,可以保证referent已经被销毁了。
即使new A()出来的对象再生了,在queue中还是可以看到WeakReference。
第一次gc后,由于new A()的对象再生了,所以queue是空的,因为对象没有销毁。
当第二次gc后,new A()的对象销毁以后,在queue中才可以看到PhantomReference。
所以PhantomReference可以更精细的对对象生命周期进行监控。
Q&A
Q1:有这样一个问题,为什么UT会Fail?不是说对象会重生吗,到底哪里有问题?
A: 对象是会重生不错。
这里会Fail有两个可能的原因,一个是gc的行为是不确定的,没有什么会保证gc运行。呵呵,我承认,我在console上看到东西了,所以我知道gc运行了一次。
另一个问题是gc的线程和我们跑ut的线程是两个独立的线程。即使gc线程里对象重生了,很有可能是我们跑完ut之后的事情了。这里就是时序问题了。
这个ut和上面那个大同小异。
一般情况下,code执行到这里,gc的对象重生应该还没有发生。所以我们下面的断言有很大的概论是成立的。
让ut的线程睡眠5秒,嗯,gc的线程有可能已经执行完对象重生了。所以下面这行有可能通过测试。
嗯,测试通过。但是没有人确保它每次都通过。所以我两处的注释都声明有可能fail。
这个例子很好的说明了如何在程序中用gc和重生的基本原则。
依赖gc会引入一些不确定的行为。
重生会导致不确定以及有可能的时序问题。
所以一般我们不应该使用gc和重生,但是能深入的理解这些概念又对我们编程有好处。
这两个测试如果作为一个TestSuite跑的话,情况又会有不同。因为第一个测试失败之后和第二个测试执行之间,gc执行了对象重生。如此,以下断言失败的概率会升高。
To luliruj and DLevin
首先谢谢你们的回复,这个帖子发了好久了,竟然还有人回复。
reclaimed的问题可以参看本帖上边的URL。
关于finalize和ReferenceQueue和关系,主贴已经解释了,luliruj给出了不同的解释。
这个地方我们可以用小程序验证一下.
在classB的finalize上打断点,然后让ref分别为SoftReference/WeakReference/PhantomReference,可以看到。
SoftReference/WeakReference都是不需要finalize执行就可以enqueue的。这个就否掉了luliruj所说的
当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放时, WeakReference 对象就被添加到它的 ReferenceQueue (如果后者存在的话)
PhantomReference必须等待finalize执行完成才可以enqueue。
这个正如主贴所说:
而PhantomReference当GC对referent的状态改变时,在把PhantomReference放入ReferenceQueue之前referent已经被GC处理到Reclaimed了,即该referent被销毁了。
这个代码有问题吧。。
既然对象销毁又再生,怎么会进入队列?
new A()这里放到外面实例化下:
大半夜,眼都花了,a忘记赋值null了
额,没注意,说晕了。
SoftReference WeakReference 在对象销毁之后,进入队列的。那finalize肯定是先执行了。
好吧。大半夜的。我都看晕。。。
说的是"不需要",我看成顺序了。。。
睡觉。。。。
额,没注意,说晕了。
SoftReference WeakReference 在对象销毁之后,进入队列的。那finalize肯定是先执行了。
这个代码有问题吧。。
既然对象销毁又再生,怎么会进入队列?
new A()这里放到外面实例化下:
我觉得这篇文章里面对PhantomReference的理解错误了。在Oracle 的 doc里面是这样说的:soft and weak references are automatically cleared by the collector before being added to the queues with which they are registered, if any. Therefore, soft and weak references need not be registered with a queue in order to be userful, while phantome references do. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.这样GC会把PhantomReference enqueue,这样如果application能够poll到的话,可以通过调用clear清理掉referent。
我觉得其实是这样,其实GC做的工作分成是两部分,第一部分是将对象从finalizable状态到finalized状态,这只是完成了资源的释放;第二部分是reclaimed对象占用的内存。其实所有在ref中的三种reference的referent的对象的reclaimed都只有在相应reference对象的clear方法调用之后,才能进行,所以,GC只是保证weakreference、softreference的clear方法被GC自动调用,并被加到referencequeue中,但是phantomreference对象在被加入到referencequeue中之前对象就已经被GC finalied(如果定义了finalize方法的话,我所指的finalized是指调用了finalize方法)了,只是还没有进行第二步reclaimed,因为phantomreference对象的clear方法还没有被调用,所以不能进行reclaimed。
我觉得这篇文章里面对PhantomReference的理解错误了。在Oracle 的 doc里面是这样说的:soft and weak references are automatically cleared by the collector before being added to the queues with which they are registered, if any. Therefore, soft and weak references need not be registered with a queue in order to be userful, while phantome references do. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.这样GC会把PhantomReference enqueue,这样如果application能够poll到的话,可以通过调用clear清理掉referent。
JDK文档中给出关于PhantomReference的解释是:
Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.
这样的描述,我的理解是在PhantomReference被Enqueue之后,它到目标引用还是存在的,要手动clear,虽然用get方法返回的还是null。这样是否表明目标引用还没有被回收。不知道你所知的reclaimed是指什么意思?而且在这一点上,我们如何做清理工作呢?我始终想不明白PhantomReference和finalizer机制是如何表现它的优势的,更直接一些,PhantomReference是如何使用的我也不是很了解,是否有人知道帮忙解释一些,谢谢。
我觉得LZ的对什么时候WeekReference和PhantomReference的解释是有问题的,与JDK文档也是相违背的,个人更倾向于以下的观点:
垃圾收集器每次运行时都可以随意地释放不再是强可及的对象占用的内存。如果垃圾收集器发现了软可及对象,就会出现下列情况:
(1)SoftReference 对象的 referent 域被设置为 null ,从而使该对象不再引用 heap 对象。
(2)SoftReference 引用过的 heap 对象被声明为 finalizable 。
(3)当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放, SoftReference 对象就被添加到它的 ReferenceQueue (如果后者存在的话)。
如果垃圾收集器发现了弱可及对象,就会出现下列情况:
(1)WeakReference 对象的 referent 域被设置为 null ,从而使该对象不再引用 heap 对象。
(2)WeakReference 引用过的 heap 对象被声明为 finalizable 。
(3)当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放时, WeakReference 对象就被添加到它的 ReferenceQueue (如果后者存在的话)。
如果垃圾收集器发现了虚可及对象,就会出现下列情况:
(1)PhantomReference 引用过的 heap 对象被声明为 finalizable 。
(2)与软引用和弱引用有所不同, PhantomReference 在堆对象被释放之前就被添加到它的 ReferenceQueue 。(请记住,所有的 PhantomReference 对象都必须用经过关联的 ReferenceQueue 来创建。)这使您能够在堆对象被回收之前采取行动。
以上摘自IBM上的一篇文章:http://www.ibm.com/developerworks/cn/java/j-refs/
JDK文档中给出关于PhantomReference的解释是:
Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.
这样的描述,我的理解是在PhantomReference被Enqueue之后,它到目标引用还是存在的,要手动clear,虽然用get方法返回的还是null。这样是否表明目标引用还没有被回收。不知道你所知的reclaimed是指什么意思?而且在这一点上,我们如何做清理工作呢?我始终想不明白PhantomReference和finalizer机制是如何表现它的优势的,更直接一些,PhantomReference是如何使用的我也不是很了解,是否有人知道帮忙解释一些,谢谢。
目录
概述
1 先看一个对象finalize的顺序问题。
2 对象再生及finalize只能执行一次
3 SoftReference WeakReference
4 PhantomReference
5 ReferenceQueue
Q&A
概述
先说一些基本的东西,GC只负责对象内存相关的清理,其他资源如文件句柄,db连接需要手动清理,以防止系统资源不足崩溃。System.gc()只是建议jvm执行GC,但是到底GC执行与否是由jvm决定的。
一个正常的对象的生命周期。
当新建一个对象时,会置位该对象的一个内部标识finalizable,当某一点GC检查到该对象不可达时,就把该对象放入finalize queue(F queue),GC会在对象销毁前执行finalize方法并且清空该对象的finalizable标识。
简而言之,一个简单的对象生命周期为,Unfinalized Finalizable Finalized Reclaimed。
Reference中引用的object叫做referent。
1 先看一个对象finalize的顺序问题。
public class A { B b; public void finalize() { System.out.println("method A.finalize at " + System.nanoTime()); } } public class B { public void finalize() { System.out.println("method B.finalize at " + System.nanoTime()); } } A a = new A(); a.b = new B(); a = null; System.gc();
按照http://java.sun.com/developer/technicalArticles/javase/finalization/
所说,对象a在finalize之前会保持b的引用,但是实验中对象a和a中的对象b的finalize方法运行时间有先有后,而且大部分时间里,a的finalize方法的执行时间是晚于b的finalize方法的。我记着java编程语言书中说是一切可以finalize的对象的finalize方法的执行顺序是不确定的。到底应该听谁的?最好的实践就是不要依赖finalize的顺序或者写一些防御代码。
【note】我仍然坚持最好的实践就是不要依赖finalize的顺序或者写一些防御代码。但是通过进一步的学习和实验,因为a有可能复活,所以在a没有决定到底复活不复活之前b是不会被回收的。控制台的顺序问题应该是多线程的问题导致的。
【note】查看了JLS后,确定了finalize是乱序执行的。
2 对象再生及finalize只能执行一次
public class B { static B b; public void finalize() { System.out.println("method B.finalize"); b = this; } } B b = new B(); b = null; System.gc(); B.b = null; System.gc();
对象b本来已经被置null,GC检查到后放入F queue,然后执行了finalize方法,但是执行finalize方法时该对象赋值给一个static变量,该对象又可达了,此之谓对象再生。
后来该static对象也被置null,然后GC,可以从结果看到finalize方法只运行了1次。为什么呢,因为第一次finalize运行过后,该对象的finalizable置为false了,所以该对象即使以后被gc运行,也不会执行finalize方法了。
很明显,对象再生是一个不好的编程实践,打乱了正常的对象生命周期。但是如果真的需要这么用的话,应该用当前对象为原型重新生成一个对象使用,这样以后这个新的对象还可以被GC运行finalize方法。
3 SoftReference WeakReference
SoftReference会尽量保持对referent的引用,直到JVM内存不够,才会回收SoftReference的referent。所以这个比较适合实现一些cache。
WeakReference不能阻止GC对referent的处理。
4 PhantomReference
幻影引用,幽灵引用,呵呵,名字挺好听的。
奇特的地方,任何时候调用get()都是返回null。那么它的用处呢,单独好像没有什么大的用处,所以要结合ReferenceQueue。
5 ReferenceQueue
ReferenceQueue WeakReference PhantomReference都有构造函数可以传入ReferenceQueue来监听GC对referent的处理。
public class A { } ReferenceQueue queue = new ReferenceQueue(); WeakReference ref = new WeakReference(new A(), queue); Assert.assertNotNull(ref.get()); Object obj = null; obj = queue.poll(); Assert.assertNull(obj); System.gc(); Assert.assertNull(ref.get()); obj = queue.poll(); Assert.assertNotNull(obj);
分析,在GC运行时,检测到new A()生成的对象只有一个WeakReference引用着,所以决定回收它,首先clear WeakReference的referent,然后referent的状态为finalizable,同时或者一段时间后把WeakReference放入监听的ReferenceQueue中。
注意有时候最后的Assert.assertNotNull(obj);有时会失败,因为还没有来的及把WeakReference放入监听的ReferenceQueue中。
换成PhantomReference试试,
ReferenceQueue queue = new ReferenceQueue(); PhantomReference ref = new PhantomReference(new A(), queue); Assert.assertNull(ref.get()); Object obj = null; obj = queue.poll(); Assert.assertNull(obj); System.gc(); Thread.sleep(10000); System.gc(); Assert.assertNull(ref.get()); obj = queue.poll(); Assert.assertNotNull(obj);
貌似和WeakReference没有什么区别呀,别急,还是有个细微的区别的,SoftReference和WeakReference在GC对referent状态改变时,先clear SoftReference/WeakReference对referent的引用,对应的referent状态为Finalizable,只是可以放入F queue,然后把SoftReference/WeakReference放入ReferenceQueue。
而PhantomReference当GC对referent的状态改变时,在把PhantomReference放入ReferenceQueue之前referent已经被GC处理到Reclaimed了,即该referent被销毁了。
搞了这么多,有什么用?可以使用PhantomReference更好的控制一些关于对象生命周期的事情,当WeakReference放入ReferenceQueue时,并不能保证该referent是被销毁了。别忘了对象可以在finalize方法里再生。而使用PhantomReference,当在ReferenceQueue中发现PhantomReference时,可以保证referent已经被销毁了。
public class A { static A a; public void finalize() { a = this; } } ReferenceQueue queue = new ReferenceQueue(); WeakReference ref = new WeakReference(new A(), queue); Assert.assertNotNull(ref.get()); Object obj = null; obj = queue.poll(); Assert.assertNull(obj); System.gc(); Thread.sleep(10000); System.gc(); Assert.assertNull(ref.get()); obj = queue.poll(); Assert.assertNotNull(obj);
即使new A()出来的对象再生了,在queue中还是可以看到WeakReference。
ReferenceQueue queue = new ReferenceQueue(); PhantomReference ref = new PhantomReference(new A(), queue); Assert.assertNull(ref.get()); Object obj = null; obj = queue.poll(); Assert.assertNull(obj); // 第一次gc System.gc(); Thread.sleep(10000); System.gc(); Assert.assertNull(ref.get()); obj = queue.poll(); Assert.assertNull(obj); A.a = null; // 第二次gc System.gc(); obj = queue.poll(); Assert.assertNotNull(obj);
第一次gc后,由于new A()的对象再生了,所以queue是空的,因为对象没有销毁。
当第二次gc后,new A()的对象销毁以后,在queue中才可以看到PhantomReference。
所以PhantomReference可以更精细的对对象生命周期进行监控。
Q&A
Q1:有这样一个问题,为什么UT会Fail?不是说对象会重生吗,到底哪里有问题?
public class Test { static Test t; @Override protected void finalize() { System.out.println("finalize"); t = this; } } public void testFinalize() { Test t = new Test(); Assert.assertNotNull(t); t = null; System.gc(); Assert.assertNull(t); Assert.assertNotNull(Test.t); }
A: 对象是会重生不错。
这里会Fail有两个可能的原因,一个是gc的行为是不确定的,没有什么会保证gc运行。呵呵,我承认,我在console上看到东西了,所以我知道gc运行了一次。
另一个问题是gc的线程和我们跑ut的线程是两个独立的线程。即使gc线程里对象重生了,很有可能是我们跑完ut之后的事情了。这里就是时序问题了。
public void testFinalize() throws Exception { Test t = new Test(); Assert.assertNotNull(t); t = null; System.gc(); Assert.assertNull(t); // 有可能fail. Assert.assertNull(Test.t); // 等一下gc,让gc线程的对象重生执行完。 Thread.sleep(5000); // 有可能fail. Assert.assertNotNull(Test.t); }
这个ut和上面那个大同小异。
一般情况下,code执行到这里,gc的对象重生应该还没有发生。所以我们下面的断言有很大的概论是成立的。
// 有可能fail. Assert.assertNull(Test.t);
让ut的线程睡眠5秒,嗯,gc的线程有可能已经执行完对象重生了。所以下面这行有可能通过测试。
Assert.assertNotNull(Test.t);
嗯,测试通过。但是没有人确保它每次都通过。所以我两处的注释都声明有可能fail。
这个例子很好的说明了如何在程序中用gc和重生的基本原则。
依赖gc会引入一些不确定的行为。
重生会导致不确定以及有可能的时序问题。
所以一般我们不应该使用gc和重生,但是能深入的理解这些概念又对我们编程有好处。
这两个测试如果作为一个TestSuite跑的话,情况又会有不同。因为第一个测试失败之后和第二个测试执行之间,gc执行了对象重生。如此,以下断言失败的概率会升高。
// 有可能fail. Assert.assertNull(Test.t);
To luliruj and DLevin
首先谢谢你们的回复,这个帖子发了好久了,竟然还有人回复。
reclaimed的问题可以参看本帖上边的URL。
关于finalize和ReferenceQueue和关系,主贴已经解释了,luliruj给出了不同的解释。
这个地方我们可以用小程序验证一下.
public class Tem { public static void main(String[] args) throws Exception { ReferenceQueue queue = new ReferenceQueue(); // SoftReference ref = new SoftReference(new B(), queue); // WeakReference ref = new WeakReference(new B(), queue); PhantomReference ref = new PhantomReference(new B(), queue); while (true) { Object obj = queue.poll(); if (obj != null) { System.out.println("queue.poll at " + new Date() + " " + obj); break; } System.gc(); System.out.println("run once."); } Thread.sleep(100000); } } class B { @Override protected void finalize() throws Throwable { System.out.println("finalize at " + new Date()); } }
在classB的finalize上打断点,然后让ref分别为SoftReference/WeakReference/PhantomReference,可以看到。
SoftReference/WeakReference都是不需要finalize执行就可以enqueue的。这个就否掉了luliruj所说的
当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放时, WeakReference 对象就被添加到它的 ReferenceQueue (如果后者存在的话)
PhantomReference必须等待finalize执行完成才可以enqueue。
这个正如主贴所说:
而PhantomReference当GC对referent的状态改变时,在把PhantomReference放入ReferenceQueue之前referent已经被GC处理到Reclaimed了,即该referent被销毁了。
评论
24 楼
在世界的中心呼喚愛
2016-09-26
在世界的中心呼喚愛 写道
public class A { static A a; public void finalize() { a = this; } } ReferenceQueue queue = new ReferenceQueue(); WeakReference ref = new WeakReference(new A(), queue); Assert.assertNotNull(ref.get()); Object obj = null; obj = queue.poll(); Assert.assertNull(obj); System.gc(); Thread.sleep(10000); System.gc(); Assert.assertNull(ref.get()); obj = queue.poll(); Assert.assertNotNull(obj);
这个代码有问题吧。。
既然对象销毁又再生,怎么会进入队列?
new A()这里放到外面实例化下:
ReferenceQueue queue = new ReferenceQueue(); A a=new A(); System.out.println("a hashcode = " +a.hashCode()); WeakReference ref = new WeakReference(a, queue); System.out.println(ref.get()); Object obj = null; obj = queue.poll(); System.out.println("1=" +obj); System.gc(); Thread.sleep(10000); System.gc(); System.out.println("2=" +ref.get()); obj = queue.poll(); System.out.println("hashcode="+a.hashCode()+" 3=" +obj);
大半夜,眼都花了,a忘记赋值null了
23 楼
在世界的中心呼喚愛
2016-09-26
在世界的中心呼喚愛 写道
在世界的中心呼喚愛 写道
在classB的finalize上打断点,然后让ref分别为SoftReference/WeakReference/PhantomReference,可以看到。
SoftReference/WeakReference都是不需要finalize执行就可以enqueue的。这个就否掉了luliruj所说的
-------------------------------------
这里我觉得表达不对,
finalize()和进入队列没有什么关系吧。
这2个东西,都是和对象销毁有关。
我觉得应该是对象销毁前进入队列,对象销毁是根据referent来的吧。。
也就是referent被销毁了,才进入队列
SoftReference/WeakReference都是不需要finalize执行就可以enqueue的。这个就否掉了luliruj所说的
-------------------------------------
这里我觉得表达不对,
finalize()和进入队列没有什么关系吧。
这2个东西,都是和对象销毁有关。
我觉得应该是对象销毁前进入队列,对象销毁是根据referent来的吧。。
也就是referent被销毁了,才进入队列
额,没注意,说晕了。
SoftReference WeakReference 在对象销毁之后,进入队列的。那finalize肯定是先执行了。
好吧。大半夜的。我都看晕。。。
说的是"不需要",我看成顺序了。。。
睡觉。。。。
22 楼
在世界的中心呼喚愛
2016-09-26
在世界的中心呼喚愛 写道
在classB的finalize上打断点,然后让ref分别为SoftReference/WeakReference/PhantomReference,可以看到。
SoftReference/WeakReference都是不需要finalize执行就可以enqueue的。这个就否掉了luliruj所说的
-------------------------------------
这里我觉得表达不对,
finalize()和进入队列没有什么关系吧。
这2个东西,都是和对象销毁有关。
我觉得应该是对象销毁前进入队列,对象销毁是根据referent来的吧。。
也就是referent被销毁了,才进入队列
SoftReference/WeakReference都是不需要finalize执行就可以enqueue的。这个就否掉了luliruj所说的
-------------------------------------
这里我觉得表达不对,
finalize()和进入队列没有什么关系吧。
这2个东西,都是和对象销毁有关。
我觉得应该是对象销毁前进入队列,对象销毁是根据referent来的吧。。
也就是referent被销毁了,才进入队列
额,没注意,说晕了。
SoftReference WeakReference 在对象销毁之后,进入队列的。那finalize肯定是先执行了。
21 楼
在世界的中心呼喚愛
2016-09-26
iteye比较少上,如果可以的话,可以发e-mail交流:christopher_y_jie@163.com
20 楼
在世界的中心呼喚愛
2016-09-26
而PhantomReference当GC对referent的状态改变时,在把PhantomReference放入ReferenceQueue之前referent已经被GC处理到Reclaimed了,即该referent被销毁了。
---------------------------------------
楼主认为Reclaimed是什么样子?
我认为的referent的销毁是等于null
referen=null。
如果referent=null,是销毁的话。
那softreference和weakreference,是销毁之后才加入队列的。也就是执行完finalize之后,才进入队列
phantomreference则是加入队列之后,才销毁的。。
以下是我测试代码:
---------------------------------------
楼主认为Reclaimed是什么样子?
我认为的referent的销毁是等于null
referen=null。
如果referent=null,是销毁的话。
那softreference和weakreference,是销毁之后才加入队列的。也就是执行完finalize之后,才进入队列
phantomreference则是加入队列之后,才销毁的。。
以下是我测试代码:
private static volatile boolean isRun = true; private static volatile ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>(); public static void main(String[] args) throws Exception { String abc = new String("abc"); System.out.println(abc.getClass() + "@" + abc.hashCode()); new Thread() { public void run() { while (isRun) { Object o = referenceQueue.poll(); if (o != null) { try { Field rereferent = Reference.class.getDeclaredField("referent"); rereferent.setAccessible(true); Object result = rereferent.get(o); //说明result是null System.out.println("gc will collect:" + result.getClass() + "@" + result.hashCode()); } catch (Exception e) { e.printStackTrace(); } } } } }.start(); // 对象是弱可达的 WeakReference<String> weak = new WeakReference<String>(abc, referenceQueue); System.out.println("weak=" + weak); // 清除强引用,触发GC abc = null; System.gc(); //等待GC被回收 Thread.sleep(3000); isRun = false; }
19 楼
在世界的中心呼喚愛
2016-09-26
在classB的finalize上打断点,然后让ref分别为SoftReference/WeakReference/PhantomReference,可以看到。
SoftReference/WeakReference都是不需要finalize执行就可以enqueue的。这个就否掉了luliruj所说的
-------------------------------------
这里我觉得表达不对,
finalize()和进入队列没有什么关系吧。
这2个东西,都是和对象销毁有关。
我觉得应该是对象销毁前进入队列,对象销毁是根据referent来的吧。。
也就是referent被销毁了,才进入队列
SoftReference/WeakReference都是不需要finalize执行就可以enqueue的。这个就否掉了luliruj所说的
-------------------------------------
这里我觉得表达不对,
finalize()和进入队列没有什么关系吧。
这2个东西,都是和对象销毁有关。
我觉得应该是对象销毁前进入队列,对象销毁是根据referent来的吧。。
也就是referent被销毁了,才进入队列
18 楼
在世界的中心呼喚愛
2016-09-26
public class A { static A a; public void finalize() { a = this; } } ReferenceQueue queue = new ReferenceQueue(); WeakReference ref = new WeakReference(new A(), queue); Assert.assertNotNull(ref.get()); Object obj = null; obj = queue.poll(); Assert.assertNull(obj); System.gc(); Thread.sleep(10000); System.gc(); Assert.assertNull(ref.get()); obj = queue.poll(); Assert.assertNotNull(obj);
这个代码有问题吧。。
既然对象销毁又再生,怎么会进入队列?
new A()这里放到外面实例化下:
ReferenceQueue queue = new ReferenceQueue(); A a=new A(); System.out.println("a hashcode = " +a.hashCode()); WeakReference ref = new WeakReference(a, queue); System.out.println(ref.get()); Object obj = null; obj = queue.poll(); System.out.println("1=" +obj); System.gc(); Thread.sleep(10000); System.gc(); System.out.println("2=" +ref.get()); obj = queue.poll(); System.out.println("hashcode="+a.hashCode()+" 3=" +obj);
17 楼
zhang_xzhi_xjtu
2014-11-11
这个看你对回收怎么理解。
如果你认为回收表示应用不可使用该对象(对象不可达),则是否执行finalize方法,和可达性关系不大,finalize里面对象可以重生。
如果你认为回收表示对象内存被回收,则没有执行finalize方法,表示对象的内存一定还没有回收掉。
如果你认为回收表示应用不可使用该对象(对象不可达),则是否执行finalize方法,和可达性关系不大,finalize里面对象可以重生。
如果你认为回收表示对象内存被回收,则没有执行finalize方法,表示对象的内存一定还没有回收掉。
zgw06629 写道
谢谢!其实主要想问的是,没有执行finalize方法, 一定表示该对象没有被回收吗?
16 楼
zgw06629
2014-11-11
谢谢!其实主要想问的是,没有执行finalize方法, 一定表示该对象没有被回收吗?
15 楼
zhang_xzhi_xjtu
2014-11-10
A a = new A();
B b = new B();
b.setA(a);
b.doSomething();
b = null;
System.gc();
这个涉及到a是否可达的判断,b=null了,但是b引用的a还是可达的。
你把这个代码放在一个小方法里面,System.gc放在方法外,就很容易看到日志了。
void f(){
A a = new A();
B b = new B();
b.setA(a);
b.doSomething();
}
void g(){
f();
System.gc();
}
B b = new B();
b.setA(a);
b.doSomething();
b = null;
System.gc();
这个涉及到a是否可达的判断,b=null了,但是b引用的a还是可达的。
你把这个代码放在一个小方法里面,System.gc放在方法外,就很容易看到日志了。
void f(){
A a = new A();
B b = new B();
b.setA(a);
b.doSomething();
}
void g(){
f();
System.gc();
}
zgw06629 写道
你好,请教一个问题.
现遇到了这么一个问题. 弄不明白特来请教.
简单描述是这样.
A a = new A();
B b = new B();
b.setA(a);
b.doSomething();
b = null;
System.gc();
B中覆盖了finalize方法(logger.info("finalize of B")).
但是控制台中没有finalize of B的输出.
但若程序中添加了如下的语句, 便有正常的输出.
b=null;
a = null; // 添加的语句
或者这样也有输出.
//A a = new A();
B b = new B();
b.setA(new A());
不明白的是, 没有调用finalize方法,到底有没有被垃圾回收呢? 这段程序是放在一个定时任务中,所以想清楚的知道该对象有没实际被回收. 除了覆盖finalize方法外,还有其他途径可以判断该对象有没被垃圾回收吗? 谢谢!
现遇到了这么一个问题. 弄不明白特来请教.
简单描述是这样.
A a = new A();
B b = new B();
b.setA(a);
b.doSomething();
b = null;
System.gc();
B中覆盖了finalize方法(logger.info("finalize of B")).
但是控制台中没有finalize of B的输出.
但若程序中添加了如下的语句, 便有正常的输出.
b=null;
a = null; // 添加的语句
或者这样也有输出.
//A a = new A();
B b = new B();
b.setA(new A());
不明白的是, 没有调用finalize方法,到底有没有被垃圾回收呢? 这段程序是放在一个定时任务中,所以想清楚的知道该对象有没实际被回收. 除了覆盖finalize方法外,还有其他途径可以判断该对象有没被垃圾回收吗? 谢谢!
14 楼
zgw06629
2014-11-10
你好,请教一个问题.
现遇到了这么一个问题. 弄不明白特来请教.
简单描述是这样.
A a = new A();
B b = new B();
b.setA(a);
b.doSomething();
b = null;
System.gc();
B中覆盖了finalize方法(logger.info("finalize of B")).
但是控制台中没有finalize of B的输出.
但若程序中添加了如下的语句, 便有正常的输出.
b=null;
a = null; // 添加的语句
或者这样也有输出.
//A a = new A();
B b = new B();
b.setA(new A());
不明白的是, 没有调用finalize方法,到底有没有被垃圾回收呢? 这段程序是放在一个定时任务中,所以想清楚的知道该对象有没实际被回收. 除了覆盖finalize方法外,还有其他途径可以判断该对象有没被垃圾回收吗? 谢谢!
现遇到了这么一个问题. 弄不明白特来请教.
简单描述是这样.
A a = new A();
B b = new B();
b.setA(a);
b.doSomething();
b = null;
System.gc();
B中覆盖了finalize方法(logger.info("finalize of B")).
但是控制台中没有finalize of B的输出.
但若程序中添加了如下的语句, 便有正常的输出.
b=null;
a = null; // 添加的语句
或者这样也有输出.
//A a = new A();
B b = new B();
b.setA(new A());
不明白的是, 没有调用finalize方法,到底有没有被垃圾回收呢? 这段程序是放在一个定时任务中,所以想清楚的知道该对象有没实际被回收. 除了覆盖finalize方法外,还有其他途径可以判断该对象有没被垃圾回收吗? 谢谢!
13 楼
zhang_xzhi_xjtu
2014-07-15
这么老的文章都能挖出来,厉害。
trytocatch 写道
呃,我是来挖坟的。
看到评论里有很多人质疑,我也来发表下自己的观点吧,支持下博主,免得后来的读者被评论误导了。
我觉得博主还是挺严谨的,我现在用的jdk是1.7,我做了好些实验,结果都跟博主说的一致,评论中的怀疑,其实只要去测试一下就可以了的。
我补充几点吧,其它的博主已经都讲到了
1、如果没有重写finalize方法,那么gc一次就被回收了;若重写了,则第一次gc只是调用finalize方法,此时可以复活,之后再gc时,如果不可达,则回收,不再调用finalize,只会调用一次。
2、对于软引用和弱引用,入队和finalize方法的执行是没有固定顺序的,可以对ReferenceQueue的入队方法和测试对象的finalize方法分别打断点,即可测试出。
3、对于“Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable”,这里说虚引用不会被垃圾收集器自动clear,其实是这样的,虚引用根本不需要clear,因为它的get本来就只会返回null,clear的目的本来就是为了让reference的get不能再获取到引用的对象,我用反射获取了一个入队后的虚引用的referent字段,并不为null,这正如上面所说的,并没有对虚引用执行clear。
看到评论里有很多人质疑,我也来发表下自己的观点吧,支持下博主,免得后来的读者被评论误导了。
我觉得博主还是挺严谨的,我现在用的jdk是1.7,我做了好些实验,结果都跟博主说的一致,评论中的怀疑,其实只要去测试一下就可以了的。
我补充几点吧,其它的博主已经都讲到了
1、如果没有重写finalize方法,那么gc一次就被回收了;若重写了,则第一次gc只是调用finalize方法,此时可以复活,之后再gc时,如果不可达,则回收,不再调用finalize,只会调用一次。
2、对于软引用和弱引用,入队和finalize方法的执行是没有固定顺序的,可以对ReferenceQueue的入队方法和测试对象的finalize方法分别打断点,即可测试出。
3、对于“Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable”,这里说虚引用不会被垃圾收集器自动clear,其实是这样的,虚引用根本不需要clear,因为它的get本来就只会返回null,clear的目的本来就是为了让reference的get不能再获取到引用的对象,我用反射获取了一个入队后的虚引用的referent字段,并不为null,这正如上面所说的,并没有对虚引用执行clear。
12 楼
trytocatch
2014-07-15
呃,我是来挖坟的。
看到评论里有很多人质疑,我也来发表下自己的观点吧,支持下博主,免得后来的读者被评论误导了。
我觉得博主还是挺严谨的,我现在用的jdk是1.7,我做了好些实验,结果都跟博主说的一致,评论中的怀疑,其实只要去测试一下就可以了的。
我补充几点吧,其它的博主已经都讲到了
1、如果没有重写finalize方法,那么gc一次就被回收了;若重写了,则第一次gc只是调用finalize方法,此时可以复活,之后再gc时,如果不可达,则回收,不再调用finalize,只会调用一次。
2、对于软引用和弱引用,入队和finalize方法的执行是没有固定顺序的,可以对ReferenceQueue的入队方法和测试对象的finalize方法分别打断点,即可测试出。
3、对于“Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable”,这里说虚引用不会被垃圾收集器自动clear,其实是这样的,虚引用根本不需要clear,因为它的get本来就只会返回null,clear的目的本来就是为了让reference的get不能再获取到引用的对象,我用反射获取了一个入队后的虚引用的referent字段,并不为null,这正如上面所说的,并没有对虚引用执行clear。
看到评论里有很多人质疑,我也来发表下自己的观点吧,支持下博主,免得后来的读者被评论误导了。
我觉得博主还是挺严谨的,我现在用的jdk是1.7,我做了好些实验,结果都跟博主说的一致,评论中的怀疑,其实只要去测试一下就可以了的。
我补充几点吧,其它的博主已经都讲到了
1、如果没有重写finalize方法,那么gc一次就被回收了;若重写了,则第一次gc只是调用finalize方法,此时可以复活,之后再gc时,如果不可达,则回收,不再调用finalize,只会调用一次。
2、对于软引用和弱引用,入队和finalize方法的执行是没有固定顺序的,可以对ReferenceQueue的入队方法和测试对象的finalize方法分别打断点,即可测试出。
3、对于“Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable”,这里说虚引用不会被垃圾收集器自动clear,其实是这样的,虚引用根本不需要clear,因为它的get本来就只会返回null,clear的目的本来就是为了让reference的get不能再获取到引用的对象,我用反射获取了一个入队后的虚引用的referent字段,并不为null,这正如上面所说的,并没有对虚引用执行clear。
11 楼
在世界的中心呼喚愛
2013-10-27
前面看懂,后面没懂。。。
10 楼
linuxfs
2013-08-03
linuxfs 写道
zhang_xzhi_xjtu 写道
答复我更新到主贴的最后了。
我觉得这篇文章里面对PhantomReference的理解错误了。在Oracle 的 doc里面是这样说的:soft and weak references are automatically cleared by the collector before being added to the queues with which they are registered, if any. Therefore, soft and weak references need not be registered with a queue in order to be userful, while phantome references do. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.这样GC会把PhantomReference enqueue,这样如果application能够poll到的话,可以通过调用clear清理掉referent。
我觉得其实是这样,其实GC做的工作分成是两部分,第一部分是将对象从finalizable状态到finalized状态,这只是完成了资源的释放;第二部分是reclaimed对象占用的内存。其实所有在ref中的三种reference的referent的对象的reclaimed都只有在相应reference对象的clear方法调用之后,才能进行,所以,GC只是保证weakreference、softreference的clear方法被GC自动调用,并被加到referencequeue中,但是phantomreference对象在被加入到referencequeue中之前对象就已经被GC finalied(如果定义了finalize方法的话,我所指的finalized是指调用了finalize方法)了,只是还没有进行第二步reclaimed,因为phantomreference对象的clear方法还没有被调用,所以不能进行reclaimed。
9 楼
linuxfs
2013-08-03
zhang_xzhi_xjtu 写道
答复我更新到主贴的最后了。
我觉得这篇文章里面对PhantomReference的理解错误了。在Oracle 的 doc里面是这样说的:soft and weak references are automatically cleared by the collector before being added to the queues with which they are registered, if any. Therefore, soft and weak references need not be registered with a queue in order to be userful, while phantome references do. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.这样GC会把PhantomReference enqueue,这样如果application能够poll到的话,可以通过调用clear清理掉referent。
8 楼
zhang_xzhi_xjtu
2012-06-27
答复我更新到主贴的最后了。
7 楼
luliruj
2012-06-25
DLevin 写道
zhang_xzhi_xjtu 写道
引入ReferenceQueue是为了更好的监视对象回收的时机,同时可以做一些自定义的动作。
这里WeakReference和PhantomReference看似一样,但是实际还是有些不一样的。
一个对象生命周期为,正常,Finalizable ,Finalized,Reclaimed。
Enqueue之前,对WeakReference,GC保证它是Finalizable,但是有可能在执行这个对象的finalize方法时对象重生。所以监视到一个WeakReference对象enqueue并不能保证该对象已经被确定性销毁。
Enqueue之前,对PhantomReference,GC保证它是reclaimed,就是说该对象已经被认为要被确定性销毁了,没有任何机会重生了。所以我们可以在这个点做一些必须保证对象被销毁才适合做的清理工作。
这里WeakReference和PhantomReference看似一样,但是实际还是有些不一样的。
一个对象生命周期为,正常,Finalizable ,Finalized,Reclaimed。
Enqueue之前,对WeakReference,GC保证它是Finalizable,但是有可能在执行这个对象的finalize方法时对象重生。所以监视到一个WeakReference对象enqueue并不能保证该对象已经被确定性销毁。
Enqueue之前,对PhantomReference,GC保证它是reclaimed,就是说该对象已经被认为要被确定性销毁了,没有任何机会重生了。所以我们可以在这个点做一些必须保证对象被销毁才适合做的清理工作。
JDK文档中给出关于PhantomReference的解释是:
Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.
这样的描述,我的理解是在PhantomReference被Enqueue之后,它到目标引用还是存在的,要手动clear,虽然用get方法返回的还是null。这样是否表明目标引用还没有被回收。不知道你所知的reclaimed是指什么意思?而且在这一点上,我们如何做清理工作呢?我始终想不明白PhantomReference和finalizer机制是如何表现它的优势的,更直接一些,PhantomReference是如何使用的我也不是很了解,是否有人知道帮忙解释一些,谢谢。
我觉得LZ的对什么时候WeekReference和PhantomReference的解释是有问题的,与JDK文档也是相违背的,个人更倾向于以下的观点:
垃圾收集器每次运行时都可以随意地释放不再是强可及的对象占用的内存。如果垃圾收集器发现了软可及对象,就会出现下列情况:
(1)SoftReference 对象的 referent 域被设置为 null ,从而使该对象不再引用 heap 对象。
(2)SoftReference 引用过的 heap 对象被声明为 finalizable 。
(3)当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放, SoftReference 对象就被添加到它的 ReferenceQueue (如果后者存在的话)。
如果垃圾收集器发现了弱可及对象,就会出现下列情况:
(1)WeakReference 对象的 referent 域被设置为 null ,从而使该对象不再引用 heap 对象。
(2)WeakReference 引用过的 heap 对象被声明为 finalizable 。
(3)当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放时, WeakReference 对象就被添加到它的 ReferenceQueue (如果后者存在的话)。
如果垃圾收集器发现了虚可及对象,就会出现下列情况:
(1)PhantomReference 引用过的 heap 对象被声明为 finalizable 。
(2)与软引用和弱引用有所不同, PhantomReference 在堆对象被释放之前就被添加到它的 ReferenceQueue 。(请记住,所有的 PhantomReference 对象都必须用经过关联的 ReferenceQueue 来创建。)这使您能够在堆对象被回收之前采取行动。
以上摘自IBM上的一篇文章:http://www.ibm.com/developerworks/cn/java/j-refs/
6 楼
DLevin
2010-10-15
zhang_xzhi_xjtu 写道
引入ReferenceQueue是为了更好的监视对象回收的时机,同时可以做一些自定义的动作。
这里WeakReference和PhantomReference看似一样,但是实际还是有些不一样的。
一个对象生命周期为,正常,Finalizable ,Finalized,Reclaimed。
Enqueue之前,对WeakReference,GC保证它是Finalizable,但是有可能在执行这个对象的finalize方法时对象重生。所以监视到一个WeakReference对象enqueue并不能保证该对象已经被确定性销毁。
Enqueue之前,对PhantomReference,GC保证它是reclaimed,就是说该对象已经被认为要被确定性销毁了,没有任何机会重生了。所以我们可以在这个点做一些必须保证对象被销毁才适合做的清理工作。
这里WeakReference和PhantomReference看似一样,但是实际还是有些不一样的。
一个对象生命周期为,正常,Finalizable ,Finalized,Reclaimed。
Enqueue之前,对WeakReference,GC保证它是Finalizable,但是有可能在执行这个对象的finalize方法时对象重生。所以监视到一个WeakReference对象enqueue并不能保证该对象已经被确定性销毁。
Enqueue之前,对PhantomReference,GC保证它是reclaimed,就是说该对象已经被认为要被确定性销毁了,没有任何机会重生了。所以我们可以在这个点做一些必须保证对象被销毁才适合做的清理工作。
JDK文档中给出关于PhantomReference的解释是:
Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.
这样的描述,我的理解是在PhantomReference被Enqueue之后,它到目标引用还是存在的,要手动clear,虽然用get方法返回的还是null。这样是否表明目标引用还没有被回收。不知道你所知的reclaimed是指什么意思?而且在这一点上,我们如何做清理工作呢?我始终想不明白PhantomReference和finalizer机制是如何表现它的优势的,更直接一些,PhantomReference是如何使用的我也不是很了解,是否有人知道帮忙解释一些,谢谢。
5 楼
zhang_xzhi_xjtu
2010-07-20
可以参考我的这个博客
http://zhang-xzhi-xjtu.iteye.com/blog/484934
讲解的更详细。
对象不会被不停地被gc(这个的gc指的是执行finalize方法)。
我想问一下,gc是如何保证WeakReference是Finalizable,PhantomReference是reclaimed。
我看到有的文章说WeakReference是在fnalize执行之后,对象被销毁之后放入referenceQueue的。
而PhantomReference是在finalize执行之后,对象被销毁之前放入refrenceQueue的。
如果都是在finalize执行之后,那如你文章中说到的,在finalize函数中使其复活后,这个对象难道还是会被标识成Finalizable,从而被放到referenceQueue中。
这样的话不是会引起该对象不停地被gc?
http://zhang-xzhi-xjtu.iteye.com/blog/484934
讲解的更详细。
对象不会被不停地被gc(这个的gc指的是执行finalize方法)。
hfhwan 写道
zhang_xzhi_xjtu 写道
引入ReferenceQueue是为了更好的监视对象回收的时机,同时可以做一些自定义的动作。
这里WeakReference和PhantomReference看似一样,但是实际还是有些不一样的。
一个对象生命周期为,正常,Finalizable ,Finalized,Reclaimed。
Enqueue之前,对WeakReference,GC保证它是Finalizable,但是有可能在执行这个对象的finalize方法时对象重生。所以监视到一个WeakReference对象enqueue并不能保证该对象已经被确定性销毁。
Enqueue之前,对PhantomReference,GC保证它是reclaimed,就是说该对象已经被认为要被确定性销毁了,没有任何机会重生了。所以我们可以在这个点做一些必须保证对象被销毁才适合做的清理工作。
这里WeakReference和PhantomReference看似一样,但是实际还是有些不一样的。
一个对象生命周期为,正常,Finalizable ,Finalized,Reclaimed。
Enqueue之前,对WeakReference,GC保证它是Finalizable,但是有可能在执行这个对象的finalize方法时对象重生。所以监视到一个WeakReference对象enqueue并不能保证该对象已经被确定性销毁。
Enqueue之前,对PhantomReference,GC保证它是reclaimed,就是说该对象已经被认为要被确定性销毁了,没有任何机会重生了。所以我们可以在这个点做一些必须保证对象被销毁才适合做的清理工作。
我想问一下,gc是如何保证WeakReference是Finalizable,PhantomReference是reclaimed。
我看到有的文章说WeakReference是在fnalize执行之后,对象被销毁之后放入referenceQueue的。
而PhantomReference是在finalize执行之后,对象被销毁之前放入refrenceQueue的。
如果都是在finalize执行之后,那如你文章中说到的,在finalize函数中使其复活后,这个对象难道还是会被标识成Finalizable,从而被放到referenceQueue中。
这样的话不是会引起该对象不停地被gc?
发表评论
-
java对象的大小_基础知识
2014-09-14 16:51 1774引言 Java的对象被jvm管理,单个对象如何布局,大小如何, ... -
xml encoding和实际编码不同导致xml解析异常
2014-04-10 09:52 5010发现一个xml encoding和实际编码不同导致xml解析异 ... -
按照bit读取或写入java的IO流
2012-11-18 22:00 3803写了个按照bit读取或写入java的IO流的简单代码,保留在博 ... -
类构造函数clinit尽量简单化
2012-01-29 16:30 1411java的类构造方法只能执行一次(不考虑多个类加载器和类卸载的 ... -
使用ImageIO.write存储png格式图片性能较差问题
2011-12-27 19:06 29334目前加载一个png格式的图片,做一些绘图工作,发现ImageI ... -
GC iCMS一次调优
2011-12-23 20:00 0原有GC参数: -server -XX:+UseParNew ... -
java集合框架类源代码阅读体会(Java Collections Framework)
2011-09-17 23:55 5037忘了什么原因突然想看下JCF,于是就有了这个阅读体会。 jav ... -
[gc] GC调优及awk脚本分析GC日志
2011-07-20 19:26 2134原有GC参数 JAVA_OPTS="-server ... -
jvm性能查看工具
2011-06-18 11:48 1606jps查看所有java进程。 jconsole jvisu ... -
[gc] java内存管理以及GC
2011-03-27 13:25 4476目录 内存管理简介 GC简介 好的Collector的特性 ... -
object的hash code
2011-01-03 19:40 2129sun的jvm默认的hash code返回的是对象的内部地址构 ... -
Enum简介
2010-08-16 21:51 1518java的Enum不同于c的命名整型常量,它本身是有类型的,而 ... -
java1.5中{@inheritDoc}的使用
2010-07-12 23:14 9606java1.5中@Override还不能用 ... -
[code] 大量只读线程安全的FastHashMap
2010-06-25 17:27 2325org.apache.commons.collections. ... -
[code] 继承TableRowSorter的一个小陷阱
2010-01-09 21:54 1295在一个JTable里面想做sorting。 继承了TableR ... -
[code] 多个线程写入,单线程读出的Stream对
2009-11-06 10:38 1739今天想做一个System.out的重定向,想要得的结果是有很多 ... -
深入理解java的finalize
2009-10-11 01:23 19292目录 基本预备相关知 ... -
深入理解java的clone
2009-10-09 14:13 4673目录 预备知识 为什么 ... -
简明OPhone/Android入门体验(有图有源码)
2009-09-25 00:34 3368主要参考 http://code.google.com/p/a ...
相关推荐
在实际编程中,`Reference`类的使用需要谨慎,因为它涉及到对Java内存模型的深入理解。过度依赖软引用可能导致内存泄漏,而滥用虚引用可能导致不必要的复杂性。正确地使用`Reference`可以帮助优化内存使用,提高应用...
为了深入理解Java内存管理,了解这四种引用类型是至关重要的。 首先,我们要了解,在JDK1.2版本之前,Java中的引用只有强引用一种,也就是说,如果一个对象有一个强引用指向它,那么这个对象就不会被垃圾收集器回收...
ReferenceQueue是一个引用队列,如果保存的是Reference对象本身,如果:Reference引用指向的对象被GC回收,其实Reference已经无效了这种Reference将被放入引用队列,可以在这里将其清除,避免占有空间。 六、...
本文将深入探讨JDK 1.6中的GC工作原理、内存分配策略以及如何进行问题排查和调优。 首先,理解GC的基本概念,其主要任务是识别并回收那些无引用指向的对象,即所谓的"dead"对象。Hotspot JVM在内存分配上有三种主要...
### 程序避免被GC回收——引用 在Java中,垃圾收集(Garbage Collection, GC)机制自动管理内存资源,有效地解决了手动管理内存时可能遇到的问题,如内存泄漏等。然而,在某些情况下,我们希望某些对象能尽可能长...
System.out.println("obj [Date: " + this.getTime() + "] is gc"); } public String toString() { return "Date: " + this.getTime(); } } ``` 在这个类中,我们对java.util.Date类进行了扩展,并重写了...
Java Reference源码解析 Java Reference是Java语言的一种机制,用于追踪对象的可达性和垃圾...通过了解Java Reference的源码,我们可以更好地理解Java的垃圾回收机制,并且能够更好地应用Java Reference在实际开发中。
ReferenceQueue<Bean> queue = new ReferenceQueue(); PhantomReference<Bean> phantom = new PhantomReference(new Bean("name", 10), queue); System.gc(); // 强制执行垃圾回收 System.out.println(phantom.get()...
本文将深入探讨Java中的四种引用类型:强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)以及幽灵引用(PhantomReference),并讨论它们在GC工作原理和性能调优中的作用。 1. 强引用...
2. `Reference(T referent, ReferenceQueue<? super T> queue)`:创建一个关联指定队列的引用对象。当对象将要被回收时,引用对象会被添加到队列中,便于外部监控。 `NULL` 队列是一个特殊队列,不会保存任何数据,...
`FinalReference`是Java内部的一个类,它是`Reference`类的子类,专为带有`finalize`方法的对象设计。每当创建一个有`finalize`方法的对象时,这个对象会被包装成一个`FinalReference`实例,并放入一个专门的引用...
总结来说,理解和合理利用Java中的`finalize()`机制、引用类型和引用队列对于优化内存管理和提升程序性能至关重要。在大多数情况下,避免使用`finalize()`,而是采用显式资源管理,如使用`try-with-resources`,以及...
在Java编程语言中,引用是连接对象实例与内存空间的关键概念。这个“java 引用相关...通过阅读“java 引用相关文档”,开发者可以深入理解Java引用机制,提升对内存管理的掌控能力,从而编写出更加高效、稳定的代码。
Java中的引用类型是Java内存管理的一个重要组成部分,特别是在理解和处理对象生命周期以及垃圾收集机制时。...在面试中能够熟练掌握和解释这些引用类型,无疑能够体现你对Java内存管理的深入理解。
Java 中 Reference 用法详解 Java 中的 Reference 类型主要分为四种:强引用、软引用、弱引用和虚引用。这些引用类型在 Java 中的使用非常广泛,特别是在缓存、池化和垃圾回收机制中。 强引用(Strong Reference)...
首先,我们来理解强引用(Strong Reference)。强引用是最常见的引用类型,它代表了程序中的普通对象引用。当一个对象被强引用指向时,该对象被认为是“可达”的,即它不会被垃圾回收器(Garbage Collector, GC)...
在Java编程语言中,`Reference`类...在面试中,理解这些概念可以帮助展示对Java内存管理的深入理解,也是编写高效、健壮的Java代码的基础。通过实践和示例代码,我们可以更好地掌握这些概念,并将其应用到实际项目中。
本文将深入探讨Java中三种特殊的引用类型——软引用(Soft Reference)、弱引用(Weak Reference)以及虚引用(Phantom Reference),并分析它们如何帮助我们更好地管理内存资源。 #### 二、基础知识回顾 在深入了解这三...
线程池调用队列是多线程编程中一个重要的概念,它在处理并发任务时起着关键作用。...此外,通过分析线程池的源码,可以帮助我们深入理解其内部工作机制,以便在遇到性能问题时能更精准地定位和解决。
虚引用主要用于对象的 finalize 回调,确保对象在 finalize 后不会被意外访问。 引用队列(ReferenceQueue)是与引用类型配合使用的工具,当弱引用或虚引用的对象被垃圾收集后,它们会自动加入到引用队列,方便程序...