0 0

关于LinkedList中的clear方法实现的疑问25

clear方法的源码如下,在代码里他循环了所有item,将其previous和next全部设置成了null,目的何在?
public void clear() {
        Entry<E> e = header.next;
        while (e != header) {
            Entry<E> next = e.next;
            e.next = e.previous = null;
            e.element = null;
            e = next;
        }
        header.next = header.previous = header;
        size = 0;
	modCount++;
    }

如果改成如下实现会有什么影响呢?其他的item都已经访问不到了,应该也不会影响GC啊。
public void clear() {
        
        header.next = header.previous = header;
        size = 0;
	modCount++;
    }

问题补充:
hareamao 写道
关键词:垃圾回收

JVM 做垃圾回收的时候应该可以发现这些item已经是不可达的,为什么还会有影响呢?

问题补充:
chen_yongkai 写道
这样做更安全,避免对象间存在相互引用而无法回收。

List add()的对象可能在list外还有引用,有可能是可达的。

首先,他这里设为null的是内部Entry对象,不是add()中的那个value;
其次,如果外部有应用,这里设成null和不设成null不是一样的,都不会被GC啊。

问题补充:
chen_yongkai 写道
Entry(a)-->Entry(b)
对象a,b都被引用了,而Entry(a).next=Entry(b),
Entry(b)被Entry(a)引用,如果在对象a,b又有相互引用,懂了吧

恩,可是无论a,b,Entry(a),Entry(b)怎么互相引用,只要没有外部引用过来,对GC来说照样是不可达的啊,还是会被GC掉得。
如果有外部引用存在,那即使这里被设成null了也照样不会被GC,还是不明他的目的何在?

问题补充:
panshaobinSB 写道
你如果只是用一部分的话,你只是清空了LinkedList对于里面所含有对象指针的释放,也就是说LinkedList不再拥有这些对象的引用了,我清空了他们,就是说我有一批苹果,我不吃了,我全部倒掉了,但是问题是:苹果呢?他们虽然被我倒掉了,但他们不会无源无故地消失吧,,,,除非这个是哈里波特的魔法世界,虽然这个我也不反对,但JVM可不这么想的吧,所以呢,这些对象并不会消亡,依然存在,可能在同时这些对象在外面还有别的对象在引用着,所以只能做多一步,就是让他们的引用全部都是null,当引用与堆间的联系没有了的话,这样才会使堆的东西孤零零的,一般在这个时候堆就会感慨:世事万千,以前一起看月亮的时候叫人家小甜甜,现在新人胜旧人,叫人家“牛夫人”,,,然后堆就会想到去死了。。。JVM这时候其实也是做好事啦,他就只好做顺水人情,当一下坏人,把堆给干掉了。。。唉。。。这种故事一般都是悲剧结尾的吧。。。苦了这些痴情的人儿啊。。。但是需要正视的问题是:LinkedList只是把自己中每个对象的引用设为null没错,那些不再被引用的对象是会被回收了,但是如果有一些对象外部还在继续用的话,也是回收不了的。举例:
String s = new String("hello");
String s2 = s;
LinkedList<String> list = new LinkedList<String>();
list.add(s);
list.clear();
System.out.println(s2);
如果还能打印出一个东西来的话,证明clear还是不会让里面的所有对象实体都消失的。

谢谢你写了这么长得故事,可是还是没解答我的疑问,我的疑问是,即使不把它们一一设成NUll,这些Entry也与这个list没有引用关联了,即使这些entry之间互相关联,可对于GC来说,这些Entry都是不可达的,应该还是可以GC掉得。

问题补充:
boy00fly 写道
引用

谢谢你写了这么长得故事,可是还是没解答我的疑问,我的疑问是,即使不把它们一一设成NUll,这些Entry也与这个list没有引用关联了,即使这些entry之间互相关联,可对于GC来说,这些Entry都是不可达的,应该还是可以GC掉得。

如果不把entity的previous、next置为null,那么就有指向堆内存(如果是一个reference)中真实对象的引用,那么堆内存的这块区域的实际对象,从gc的原理来讲:他并非root不可触及的,所以不可回收。


这些怎么会是root可及的呢?应该不会有栈桢中的变量会引用到这些entry吧,也不会有静态变量引用过来,

关于GC roots,推荐你看下http://icyfenix.iteye.com/blog/802638这个博客,最近看到这个博客,感觉学到不少,也才会有现在的疑问。

问题补充:
jacky1118sally 写道
next引用,引用并没有被销毁,不是所以gc 是不会回收的,仍然存在,感觉是这样。

这些entry内部还有互相引用,但已经没有外部的引用指向这些entry了。
例如下面的代码,方法testMethod返回后,你说a1和a2会不会被回收,他们之间存在着互相引用,虽然没有外部引用指向他们了

class A{
   A a;

}
public class Test{
   public void testMethod(){
       A a1=new A();
       A a2=new A();
       a1.a=a2;
       a2.a=a1;
   }
}

问题补充:
qingming.com 写道
如果list里的元素没有外部引用是可以的。也是等效的。
但是如果有一个元素被外部引用,那么对象的链还是可达的,导致list里的所以对象都可达而不会被JVM回收。
如果照jdk中设计的clear时把链拆开,那么就算外部有一个对list里某一元素的引用,也不会影响到其他的元素了,只影这一个元素。
list是个线性的链,实际对象的关系引用是一个立体图。


可能你没看清楚代码,这些元素都是存在entry里的,即使外部有对里面某个元素的引用,也不会引用到这个entry,entry对象照样是可以被回收的吧。。

问题补充:
jacky1118sally 写道
使用楼主的 代码
引用

class A{   
   A a;   
} 
public class Test{   
   public void testMethod(){   
       A a1=new A();   
       A a2=new A();   
       a1.a=a2;   
       a2.a=a1;   
   }   
}  




我进行了改写
        public void testMethod(){   
	       A a1=new A();   
	       A a2=new A();   
	       a1.a=a2;   
	       a2.a=a1;
	      // a1 = null;
	      // a2 = null;
	       System.gc();//调用GC
	   }  
   class A{   
	   A a;   
	  protected  void finalize() {
	   System.out.println("垃圾回收了");
	 
	}  

如果如楼主所写,那么console 是不输出的,因为gc不会回收,虽然没有外部指向两个对象,但是他们的属性有引用存在。
如果去掉注释,也就是 使 a1,a2 为null 则会输出 “垃圾回收了” 说明gc调用了finalize方法,进行了回收。
所以 上面的 例子 每个 entry 为空才行。

呃。。我想你可能没看清楚,这里你要是设成null了就相当于LinkedList里把其他entry和header之间的关系断掉一样,但其他entry之间的互相引用还在,就如a1和a2这两个对象内有互相引用一样,他们仍然可以被回收,不需要设置a1.a=null以及a2.a=null,这也是我问为什么需要设置e.next = e.previous = null的原因,应该不会影响GC才对。

问题补充:
boy00fly 写道
引用
这些怎么会是root可及的呢?应该不会有栈桢中的变量会引用到这些entry吧,也不会有静态变量引用过来,

关于GC roots,推荐你看下http://icyfenix.iteye.com/blog/802638这个博客,最近看到这个博客,感觉学到不少,也才会有现在的疑问。


我们来分析下,为什么说这些entity有可能是root可触及的呢?
首先Entity作为LinkedList的内部静态类,LinkedList的引用是存在对每个Entity对象的引用的,有可能你的LinkedList的对象只是作为局部变量使用,出了方法的栈帧就没用了,是没错,但是作为类库的笔者的话,他本是并不知道你的LinkedList对象是怎么使用的,如果你的LinkedList作为一个类变量存在的话会是什么样的情况呢? 只要你当前类没有卸载,你的LinkedList的对象就一直会存在,接着你的每个Entity指向的堆内存的数据就会一直存在着引用,所以说时root可触及的,clear方法中的while循环的作用就是为了防止类似这样的情况方法,确保无用的数据可以垃圾回收。

我的意思是不一一设置成null,只是把header所指向的引用改下,这样不是照样在linkedlist对象里没有对剩下那些entry的引用了么?剩下那些entry不是应该还是可以被GC么?

问题补充:
chen_yongkai 写道
还在讨论啊?
不管怎样,良好的编程习惯是必须的!
每段代码都应该做好自己的职责,特别是对于公用类。
如果你都不做好撤销引用,保证GC的工作;那调用者如果也没做好这部分工作,那么内存垃圾就会不断累积

恩,我同意你的观点,也认为这些公共类这么写是有他的用意的,只是从我认知的角度来看,它加不加那个while应该都会被回收才对,那它加了while是有什么作用的呢?

问题补充:
jacky1118sally 写道
上次好像是我没说好,不好意思
我这样说吧  楼主看看   有说服力么
public void testMethod(){   
	       A a1=new A();   
	       A a2=new A();   
	       a1.a=a2;   
	       a2.a=a1;
	       
	       //a2.a= null;
	         a1 = null;
	       System.gc();
	   }   

class A 不变。
如果是这样的话,虽然销毁了a1 ,但是gc并不会回收a1,因为 a2.a=a1;引用的存在
这个地址仍然是在的。如果去掉了 注释,使a2.a= null; 这样a1 就可以被销毁了,因为所有关于它的引用都没了。
所以 clear方法就清除了 所有的引用,不然虽然list不再需要他们,但是之间的引用是存在的,所以需要那个while循环,来给他们置空。

不好意思,我现在用手机上网,没办法说得太详细,不过你说的情况和我提的问题有点不太一致,我晚些时候画个图你看看就明白了

问题补充:
boy00fly 写道
引用
我的意思是不一一设置成null,只是把header所指向的引用改下,这样不是照样在linkedlist对象里没有对剩下那些entry的引用了么?剩下那些entry不是应该还是可以被GC么?

哦,我明白你的意思了,确实如你所说如果是根据根节点搜索算法判断对象是否可回收的话,确实没有必要了。可能这个也有历史或者其他的原因,在早期的时候有些JVM采用的是引用计数算法,采用这种算法的时候如果不做while循环的操作,就可能会有问题了。例如:LinkedList所存放的真实的堆内存对象必须在entity对象被回收后,才有可能被回收。

呵呵,感觉不太像是因为历史原因,因为每个JDK的发布,都有配套的GC算法,应该不会现在的代码还用原来的GC吧…

问题补充:
jkxydp 写道
header.next = header.previous = header;
光这样怎么会有用呢?
这样的话header指针还指向原来的单元,对吧原来的单元还存着头结点中的对象,不是吗?
注意这句:
e.next = e.previous = null;
因为LinkedList是双向循环链表。
执行
header.next = header.previous = header;
之后,头节点是没有指向别的节点了,但是别的节点还指向它的上一个结点,并且别的节点也指向下一个节点,也就是说头结点下一个节点的next-->下一个节点,而头结点的下一个节点的pre-->header,这样头节点本身释放不了,header的下一个节点也释放不了,因为它的下一个节点的下一个节点的pre-->hreder的下一个节点。
以此类推,那块代码是不能去掉的,而且很关键。

给分吧楼主。

囧…建议你把前面的讨论看下吧…

问题补充:这样跟你说吧:
String a = new String("123456")

问题补充:
jkxydp 写道
这样跟你说吧:
String a = new String("123456");
String b = new String("2356");
String c = new String("2356");
String d = new String("2356");

LinkedList<String> ll = new LinkedList<String>();
ll.add(a);
ll.add(b);
ll.add(c);
ll.add(d);

ll.clear();

如果没有那个循环就成了什么样子呢?
b有一个引用指向entry(b)中的值,entry(b)的pre->entry(a),entry(b)的next-->entry(c);如果不执行让他们指向null,a,b,c,d的引用任然指向这个list的元素,而list的元素之间也有相互指向,只要在a,b,c,d中存在一个没有被销毁,那么这一大块内存都会一直被占用,不晓得你现在会不会有点明白。

就好比一个对象里面有一个对象被一个该对象外部的引用持有,那么这个对象是绝对不能被回收的,如果这样还被回收,那java就写不出什么稳定的程序了。


那最后那句总结的话我怎么看怎么别扭,你的意思是说,如果A,B共同持有C的引用,A就不可能被回收?如果你是这个意思,我就理解不能了,为什么不能回收?

还是说你指的是C不能被回收,只要A和B任何一个不能被回收,C就不会被回收,这我可以理解,但和我们讨论的这个情况有什么关系么?

问题补充:
chaliszhou 写道
哈哈,这么简单的问题,弄了这半天,哎,累不累啊,你的精神值得我们学习,给点分吧!哈哈。

不懂…奈何,望指点

问题补充:
jkxydp 写道


看一下这个对象的简单堆栈图吧,这是不使用循环语句,执行clear语句之后的情形。

其中栈里面a,b,c,d,指向的是entry里面的数据节点,entry上的箭头指的是pre和next引用.

你的意思我懂了,但我觉得你可能弄错了一点,我觉得正确的图应该是这样的:

如果没有那个循环,就是把图中两条红色的指向改成执行“entry实例-header”里,这个时候你就发现“entry实例-a”和“entry实例-b”这个两个实例已经没有外部引用了,就是说已经不影响回收器对这两个实例的回收了。即使这两个实例被回收了,也不会应影响到栈中对a和b两个实例的引用。


chaliszhou 写道
再仔细看看源代码,和你改后的区别,源代码都是牛人写的一般,绝对安全可靠!


恩,我不否认源码这么写有它的用意在,而我就是在学习它,试图理解它的用意。


问题补充:
bjmike 写道
应该是垃圾回收的效率问题,当linkedlist存放大量元素时,调用clear()后,会使过期的元素数据最快被回收。因为gc总是先判断为null的引用对象,其次才是内存中的互相引用的对象构成的孤岛,如果这个孤岛很大,这样gc判断起来会很耗资源,效率也就降低了。

能说得更详细点么?比如gc如何判断为null的引用对象,和判断孤岛用的方式有什么不一样么?

我看过的一些GC的资料说判断对象是否可以GC,是通过看GC roots是否可以达到那个对象,如果是这样的话,前面说的两种情况应该一样的才对。

问题补充:
jkxydp 写道


其中栈里面a,b,c,d,指向的是entry里面的数据节点,entry上的箭头指的是pre和next引用.


刚才图片可能有问题。。
2011年9月08日 17:16
  • 大小: 33.6 KB

30个答案 按时间排序 按投票排序

0 0

采纳的答案

看了楼主的图之后我觉得自己之前搞错了,先向楼主和看客道个歉。
但是这也并非楼主说的加快GC回收那么简单。
为了这个我便仔细地去读了一下LinkedList的源代码,原来发现惑起Iterator。

private class ListItr implements ListIterator<E> {
	private Entry<E> lastReturned = header;
	private Entry<E> next;
	private int nextIndex;
	private int expectedModCount = modCount;

	ListItr(int index) {
	    if (index < 0 || index > size)
		throw new IndexOutOfBoundsException("Index: "+index+
						    ", Size: "+size);
	    if (index < (size >> 1)) {
		next = header.next;
		for (nextIndex=0; nextIndex<index; nextIndex++)
		    next = next.next;
	    } else {
		next = header;
		for (nextIndex=size; nextIndex>index; nextIndex--)
		    next = next.previous;
	    }
	}

	public boolean hasNext() {
	    return nextIndex != size;
	}

	public E next() {
	    checkForComodification();
	    if (nextIndex == size)
		throw new NoSuchElementException();

	    lastReturned = next;
	    next = next.next;
	    nextIndex++;
	    return lastReturned.element;
	}
......
}

如源代码所示,如果程序员对该List对象使用过iterator,并且迭代到中间就断了,那么栈内就会有一个引用指向Iterator对象,而Iterator对象中又有lastReturned 引用指向一个Entry再结合上图就不难理解整条链得不到释放,GC不能回收的疑惑了。

郑重地向楼主道歉,之前我真向简单了点。
不过该观点估计也不一定对,有鉴于之前的幼稚的想法。

2011年9月21日 08:50
0 0

設置為null的對象,首先釋放了他所占用的內存空間,java垃圾回收機制中首先會回收這類對象。

2011年9月21日 10:00
0 0

说简单点不明白,你接着头疼吧,那个对象中
有多个元素,你把那个对象中的元素之间的关系都摸掉了,按照你的意思是gc应该回收这个对象。可是偏偏没有。你就纠结在这里了,前面很多人回答都对了啊。你砸还纠结呢!!!

举个例子:你有一个衬衫,上面有8个扣子,假如他们都扣起来时作为一个对象。难道你把他们都从衬衫上扯下来,这些扣子就没用了吗?

还不明白,不要学习源代码了,对你来说是种折磨!!!

2011年9月21日 08:22
0 0

应该是垃圾回收的效率问题,当linkedlist存放大量元素时,调用clear()后,会使过期的元素数据最快被回收。因为gc总是先判断为null的引用对象,其次才是内存中的互相引用的对象构成的孤岛,如果这个孤岛很大,这样gc判断起来会很耗资源,效率也就降低了。

2011年9月20日 21:35
0 0

看看 回收策略,http://icyfenix.iteye.com/blog/802638,我刚看了下,还不错了,这个已经有人发给你了!

2011年9月20日 18:08
0 0

再仔细看看源代码,和你改后的区别,源代码都是牛人写的一般,绝对安全可靠!

2011年9月20日 17:55
0 0



看一下这个对象的简单堆栈图吧,这是不使用循环语句,执行clear语句之后的情形。

其中栈里面a,b,c,d,指向的是entry里面的数据节点,entry上的箭头指的是pre和next引用.

2011年9月20日 14:59
0 0

你看了我发给你的站内信还不能明白?
那我也没法儿讲得再明白了,堆栈图里面一目了然。
一般Entry的简单定义都是内部类的方式:
private class Entry{
    private Entry pre;
    private Entry next;
    private Object data;
}

LinkedList的add方法把传入的参数写到data中,如果data的引用存在,并且Entry的pre、next又指向了别的Entry对象,你觉得这整条对象链能被回收吗?
实在弄不明白我也就木得办法咯。

2011年9月20日 14:53
0 0

哈哈,这么简单的问题,弄了这半天,哎,累不累啊,你的精神值得我们学习,给点分吧!哈哈。

2011年9月20日 12:41
0 0

已经发了站内信给你了,你一看估计就明白了。

2011年9月20日 10:52
0 0

你把邮箱给我吧,我画了个图,你看了估计就明白了,但是我现在在上班,因为是银行里面,什么都要权限,图片也不好传,就可以写邮件。

2011年9月20日 10:44
0 0

这样跟你说吧:
String a = new String("123456");
String b = new String("2356");
String c = new String("2356");
String d = new String("2356");

LinkedList<String> ll = new LinkedList<String>();
ll.add(a);
ll.add(b);
ll.add(c);
ll.add(d);

ll.clear();

如果没有那个循环就成了什么样子呢?
b有一个引用指向entry(b)中的值,entry(b)的pre->entry(a),entry(b)的next-->entry(c);如果不执行让他们指向null,a,b,c,d的引用任然指向这个list的元素,而list的元素之间也有相互指向,只要在a,b,c,d中存在一个没有被销毁,那么这一大块内存都会一直被占用,不晓得你现在会不会有点明白。

就好比一个对象里面有一个对象被一个该对象外部的引用持有,那么这个对象是绝对不能被回收的,如果这样还被回收,那java就写不出什么稳定的程序了。

2011年9月16日 10:30
0 0

header.next = header.previous = header;
光这样怎么会有用呢?
这样的话header指针还指向原来的单元,对吧原来的单元还存着头结点中的对象,不是吗?
注意这句:
e.next = e.previous = null;
因为LinkedList是双向循环链表。
执行
header.next = header.previous = header;
之后,头节点是没有指向别的节点了,但是别的节点还指向它的上一个结点,并且别的节点也指向下一个节点,也就是说头结点下一个节点的next-->下一个节点,而头结点的下一个节点的pre-->header,这样头节点本身释放不了,header的下一个节点也释放不了,因为它的下一个节点的下一个节点的pre-->hreder的下一个节点。
以此类推,那块代码是不能去掉的,而且很关键。

给分吧楼主。

2011年9月15日 15:40
0 0

引用
呵呵,感觉不太像是因为历史原因,因为每个JDK的发布,都有配套的GC算法,应该不会现在的代码还用原来的GC吧…

当然现有的代码没有用原来的GC,有可能是为了保持这种兼容性或者说写这个类的程序员太懒或者也没注意到,哈哈,纯粹猜想。坐等高人解释吧!

2011年9月15日 14:37
0 0

引用
我的意思是不一一设置成null,只是把header所指向的引用改下,这样不是照样在linkedlist对象里没有对剩下那些entry的引用了么?剩下那些entry不是应该还是可以被GC么?

哦,我明白你的意思了,确实如你所说如果是根据根节点搜索算法判断对象是否可回收的话,确实没有必要了。可能这个也有历史或者其他的原因,在早期的时候有些JVM采用的是引用计数算法,采用这种算法的时候如果不做while循环的操作,就可能会有问题了。例如:LinkedList所存放的真实的堆内存对象必须在entity对象被回收后,才有可能被回收。

2011年9月15日 12:28
0 0

还在讨论啊?
不管怎样,良好的编程习惯是必须的!
每段代码都应该做好自己的职责,特别是对于公用类。
如果你都不做好撤销引用,保证GC的工作;那调用者如果也没做好这部分工作,那么内存垃圾就会不断累积

2011年9月15日 10:03
0 0

上次好像是我没说好,不好意思
我这样说吧  楼主看看   有说服力么

public void testMethod(){   
	       A a1=new A();   
	       A a2=new A();   
	       a1.a=a2;   
	       a2.a=a1;
	       
	       //a2.a= null;
	         a1 = null;
	       System.gc();
	   }   

class A 不变。
如果是这样的话,虽然销毁了a1 ,但是gc并不会回收a1,因为 a2.a=a1;引用的存在
这个地址仍然是在的。如果去掉了 注释,使a2.a= null; 这样a1 就可以被销毁了,因为所有关于它的引用都没了。
所以 clear方法就清除了 所有的引用,不然虽然list不再需要他们,但是之间的引用是存在的,所以需要那个while循环,来给他们置空。

2011年9月15日 09:35
0 0

引用
这些怎么会是root可及的呢?应该不会有栈桢中的变量会引用到这些entry吧,也不会有静态变量引用过来,

关于GC roots,推荐你看下http://icyfenix.iteye.com/blog/802638这个博客,最近看到这个博客,感觉学到不少,也才会有现在的疑问。


我们来分析下,为什么说这些entity有可能是root可触及的呢?
首先Entity作为LinkedList的内部静态类,LinkedList的引用是存在对每个Entity对象的引用的,有可能你的LinkedList的对象只是作为局部变量使用,出了方法的栈帧就没用了,是没错,但是作为类库的笔者的话,他本是并不知道你的LinkedList对象是怎么使用的,如果你的LinkedList作为一个类变量存在的话会是什么样的情况呢? 只要你当前类没有卸载,你的LinkedList的对象就一直会存在,接着你的每个Entity指向的堆内存的数据就会一直存在着引用,所以说时root可触及的,clear方法中的while循环的作用就是为了防止类似这样的情况方法,确保无用的数据可以垃圾回收。

2011年9月15日 08:38
0 0

使用楼主的 代码

引用

class A{   
   A a;   
} 
public class Test{   
   public void testMethod(){   
       A a1=new A();   
       A a2=new A();   
       a1.a=a2;   
       a2.a=a1;   
   }   
}  




我进行了改写
        public void testMethod(){   
	       A a1=new A();   
	       A a2=new A();   
	       a1.a=a2;   
	       a2.a=a1;
	      // a1 = null;
	      // a2 = null;
	       System.gc();//调用GC
	   }  
   class A{   
	   A a;   
	  protected  void finalize() {
	   System.out.println("垃圾回收了");
	 
	}  

如果如楼主所写,那么console 是不输出的,因为gc不会回收,虽然没有外部指向两个对象,但是他们的属性有引用存在。
如果去掉注释,也就是 使 a1,a2 为null 则会输出 “垃圾回收了” 说明gc调用了finalize方法,进行了回收。
所以 上面的 例子 每个 entry 为空才行。

2011年9月14日 22:45
0 0

如果list里的元素没有外部引用是可以的。也是等效的。
但是如果有一个元素被外部引用,那么对象的链还是可达的,导致list里的所以对象都可达而不会被JVM回收。
如果照jdk中设计的clear时把链拆开,那么就算外部有一个对list里某一元素的引用,也不会影响到其他的元素了,只影这一个元素。
list是个线性的链,实际对象的关系引用是一个立体图。

2011年9月14日 22:21
0 0

next引用,引用并没有被销毁,不是所以gc 是不会回收的,仍然存在,感觉是这样。

2011年9月14日 17:04
0 0

引用

谢谢你写了这么长得故事,可是还是没解答我的疑问,我的疑问是,即使不把它们一一设成NUll,这些Entry也与这个list没有引用关联了,即使这些entry之间互相关联,可对于GC来说,这些Entry都是不可达的,应该还是可以GC掉得。

如果不把entity的previous、next置为null,那么就有指向堆内存(如果是一个reference)中真实对象的引用,那么堆内存的这块区域的实际对象,从gc的原理来讲:他并非root不可触及的,所以不可回收。

2011年9月14日 10:04
0 0

第二张图画错了,header的previous、next应该指向header本身。

2011年9月14日 09:30
0 0


|
|
|

这样的话,楼主能够看出端倪了吗?

2011年9月14日 09:26
0 0

Entry<E> e = header.next;      
while (e != header) {          
    Entry<E> next = e.next;    
    e.next = e.previous = null;
    e.element = null;          
    e = next;                  
}                               

上面这段代码的作用就是将链表中除header的每个元素的previous、next均置为null,这样做原因就是为了方便垃圾回收!
如果不这样做的话,当前链表的元素会被其他元素所引用,导致无法gc(存在循环引用)!
关于LinkedList的源码分析可参考http://boy00fly.iteye.com/blog/1138904

2011年9月14日 09:07
0 0

你如果只是用一部分的话,你只是清空了LinkedList对于里面所含有对象指针的释放,也就是说LinkedList不再拥有这些对象的引用了,我清空了他们,就是说我有一批苹果,我不吃了,我全部倒掉了,但是问题是:苹果呢?他们虽然被我倒掉了,但他们不会无源无故地消失吧,,,,除非这个是哈里波特的魔法世界,虽然这个我也不反对,但JVM可不这么想的吧,所以呢,这些对象并不会消亡,依然存在,可能在同时这些对象在外面还有别的对象在引用着,所以只能做多一步,就是让他们的引用全部都是null,当引用与堆间的联系没有了的话,这样才会使堆的东西孤零零的,一般在这个时候堆就会感慨:世事万千,以前一起看月亮的时候叫人家小甜甜,现在新人胜旧人,叫人家“牛夫人”,,,然后堆就会想到去死了。。。JVM这时候其实也是做好事啦,他就只好做顺水人情,当一下坏人,把堆给干掉了。。。唉。。。这种故事一般都是悲剧结尾的吧。。。苦了这些痴情的人儿啊。。。但是需要正视的问题是:LinkedList只是把自己中每个对象的引用设为null没错,那些不再被引用的对象是会被回收了,但是如果有一些对象外部还在继续用的话,也是回收不了的。举例:
String s = new String("hello");
String s2 = s;
LinkedList<String> list = new LinkedList<String>();
list.add(s);
list.clear();
System.out.println(s2);
如果还能打印出一个东西来的话,证明clear还是不会让里面的所有对象实体都消失的。

2011年9月10日 16:30
0 0

Entry(a)-->Entry(b)
对象a,b都被引用了,而Entry(a).next=Entry(b),
Entry(b)被Entry(a)引用,如果在对象a,b又有相互引用,懂了吧

2011年9月09日 08:21
0 0

这样做更安全,避免对象间存在相互引用而无法回收。

List add()的对象可能在list外还有引用,有可能是可达的。

2011年9月08日 17:59
0 0

我猜的是不是和内存有关啊,设为null后,垃圾处理器应该会回收对象的吧。

2011年9月08日 17:19
0 0

关键词:垃圾回收

2011年9月08日 17:19

相关推荐

    链表类LinkedList的完全c++实现

    链表类LinkedList的完全c++实现,根据数据结构与算法课堂总结。

    测试ArrayList和LinkedList的add方法

    测试ArrayList和LinkedList的add方法

    容器中基于链路的linkedList方法的底层实现

    容器中基于链路的linkedList方法的底层实现

    LinkedList的实现.zip

    在这个“LinkedList的实现.zip”文件中,我们有三个头文件——Link.h、List.h和LinkedList,它们共同构成了LinkedList的数据结构及其操作的实现。 首先,`Link.h`通常会定义单链表中的节点结构。节点结构可能包括一...

    源码解析jdk7.0集合:LinkedList的底层实现原理.pdf

    带有参数的构造方法接收一个实现了Collection接口的对象,然后将集合中的所有元素添加到LinkedList中。这个过程是通过调用addAll方法来实现的。 LinkedList添加元素的操作主要有三种情形:在链表头部添加、在链表...

    java中LinkedList集合类实现栈和队列.doc

    在Java编程语言中,LinkedList集合类是一个非常重要的数据结构,它可以用来实现栈和队列这两种特殊的数据结构。LinkedList是一个双链表,每个节点包含数据元素和两个引用,分别指向前后节点,这使得在列表中进行插入...

    JavaScript 实现基础 LinkedList 功能

    在JavaScript中实现LinkedList,我们需要理解其基本概念、操作以及如何用原生JavaScript对象来模拟链表结构。 首先,LinkedList由一系列节点(Node)组成,每个节点包含两部分:数据和指向下一个节点的引用。在...

    LinkedList实现List一些方法

    在本文中,我们将深入探讨LinkedList如何实现List接口的一些主要方法,并了解其内部工作原理。 1. **添加元素**: LinkedList提供了`add(int index, E element)`和`add(E e)`方法来添加元素。`add(int index, E ...

    使用LinkedList模拟堆栈

    在Java中,LinkedList同样可以用于实现队列,主要通过addLast()和removeFirst()方法。 以下是使用LinkedList模拟队列的实现: 1. 创建LinkedList实例。 ```java LinkedList&lt;Object&gt; queue = new LinkedList(); ```...

    用LinkedList实现队列和栈

    在Java编程语言中,`LinkedList` 是一个常用的集合类,它实现了`List`接口,并且提供了额外的功能,如双端操作。本篇文章将探讨如何利用`LinkedList`来实现队列和栈这两种数据结构,以及其背后的原理和源码分析。 #...

    java中LinkedList任意排序实例

    在Java编程中,LinkedList是一个非常重要的数据结构,它实现了List接口,允许我们在列表的任何位置进行插入和删除操作。LinkedList内部使用双向链表实现,因此它的遍历速度比ArrayList快,但随机访问性能较差。本...

    LinkedList 所有公有方法和属性 导图

    .NET框架中的LinkList,实现的是双向链表,总结下它的实现源码。 LinkedList提供的公有属性和方法的导图

    LinkedList实现栈

    在Java中,我们可以使用LinkedList的`push()`方法来模拟栈的压栈操作,即向栈顶添加元素;使用`pop()`方法来模拟栈的弹栈操作,即移除并返回栈顶元素。为了确保线程安全,我们需要在多线程环境下对这些操作进行同步...

    ArrayList LinkedList Vector区别

    LinkedList、ArrayList、Vector 都实现了 List 接口,它们在实际应用中有不同的使用场景。LinkedList 可以被用作堆栈、队列或双向队列,ArrayList 可以用于实现大规模数据存储,Vector 可以用于实现线程安全的数据...

    JAVA利用LinkedList构造栈与队列

    在Java编程语言中,LinkedList是一个常用的集合类,它实现了List接口,同时也提供了双向链表的实现。LinkedList不仅可以作为列表使用,还可以被巧妙地利用来构建栈(Stack)和队列(Queue)这两种基本数据结构。在本...

    Go-LinkedList一个简单的双链表实现

    对于提供的压缩包文件"itsmontoya-linkedlist-1aa2446",我们可以通过查看源代码来深入了解上述功能的具体实现,包括节点结构、链表操作方法的内部逻辑以及可能的优化策略。源代码通常会包含详细的注释和示例,帮助...

    Kotlin中Stack与LinkedList的实现方法示例

    本文将深入探讨如何在Kotlin中实现Stack(栈)和LinkedList(链表)这两种常见的数据结构,并通过示例代码展示它们的主要功能。 首先,我们来看Kotlin中的Stack实现。栈是一种后进先出(LIFO)的数据结构,通常用于...

    Java实现LinkedList

    实现一个链表LinkedList,要求使用链表机构实现,并提供相应的add(Object o),remove(Object o)这两个方法.

    Java 中Linkedlist类的源代码

    在Java编程语言中,LinkedList是一个实现List接口的类,它以双向链表的形式存储元素。这个数据结构允许我们在列表的任何位置进行插入和删除操作,具有O(1)的时间复杂度,这使得LinkedList在需要频繁进行这些操作时比...

    关于arraylist和linkedList的区别

    ### 关于ArrayList与LinkedList的区别 在Java编程语言中,`ArrayList`与`LinkedList`都是`List`接口的具体实现类,用于存储元素集合。虽然它们都实现了同样的接口并且提供了相同的基本功能,但在内部实现机制、性能...

Global site tag (gtag.js) - Google Analytics