关于JAVA的垃圾收集与对象创建的问题 两种方法差不了多少的第二种方法也没有创建很多的对象,他创建的只是句柄,对象本来都是存在了的(list初期化的时候他们就存在了),你循环里面只是创建句柄指向这些对象。句柄占用空间不是很大的。可以的话还是用第一种吧(个人看法) 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 呵呵,俺与“bluesmile979(笑着)”持相反的观点。当然是第二种!原因有两处:(1) 两种做法对于垃圾收集的影响没有本质的差别,可以忽略之;(2) 关键的原因:临时变量的作用域问题。临时变量的作用域应该最小化;由此可以引出一个关于循环的问题,就是for循环优于while循环:<<for(Iterator it=list.iterator(); it.hasNext(); ) { Object each = it.next();}优于Iterator it=list.iterator();while( it.hasNext() ) { Object each = it.next();}>>在上面这两个例子中,Iterator it这个临时变量的作用域是不同的。 public class CTest{ public static void main(String[] args){ System.out.println("Started:"); long time=System.currentTimeMillis(); //Integer a; for(int i=0;i<100000000;i++){ Integer a=new Integer(i); } System.out.println("accomplished:"+String.valueOf(System.currentTimeMillis()-time)); }}运行时间前者5601ms后者5518ms(不同机子上和不同时间运行都有可能不同)两者基本上不分上下 两种方式区别不大,看看下面是两个方法的java字节码方法一public void M1(); Code: 0: aconst_null 1: astore_1 2: iconst_0 3: istore_2 4: goto 23 7: aload_0 8: getfield #2; //Field list:Ljava/util/Vector; 11: iload_2 12: invokevirtual #3; //Method java/util/Vector.get:(I)Ljava/lang/Object; 15: checkcast #4; //class ClassA 18: astore_1 19: nop 20: iinc 2, 1 23: iload_2 24: aload_0 25: getfield #2; //Field list:Ljava/util/Vector; 28: invokevirtual #5; //Method java/util/Vector.size:()I 31: if_icmplt 7 34: nop 35: return方法二public void M2(); Code: 0: iconst_0 1: istore_1 2: goto 21 5: aload_0 6: getfield #2; //Field list:Ljava/util/Vector; 9: iload_1 10: invokevirtual #3; //Method java/util/Vector.get:(I)Ljava/lang/Object; 13: checkcast #4; //class ClassA 16: astore_2 17: nop 18: iinc 1, 1 21: iload_1 22: aload_0 23: getfield #2; //Field list:Ljava/util/Vector; 26: invokevirtual #5; //Method java/util/Vector.size:()I 29: if_icmplt 5 32: nop 33: return}方法一的4-35行同方法二的2-33行基本一致,但方法一比方法二多了1-2行 0: aconst_null 1: astore_1是用来初始化ClassA a = null的,所以方法一比方法二多一个初始化a的时间如果少量调用这两个方法的话,区别不太大,但如果频繁调用这方法的话,还是方法二的性能稍微优越一点,调用两个方法循环10000次结果如下第一个4484第二个4469 呵呵,jjj3000(jjj3000) 分析得不错。但是这个问题其实不在执行效率的区别之上,还是和之前提到的,是局部变量的作用域的问题。 TO alienbat(死灵巫师):不同意。你为什么会认为第二种方法产生的垃圾对象会比第一种多?在楼主的例子中,实际上两种方法都不会有什么垃圾对象。这些对象的引用始终被List保持,不会被垃圾收集。其实看看第一种方法和第二种方法的区别,jjj3000(jjj3000) 反编译出来的字节码就可以展示清楚了。在循环体中除去循环控制语句不管,区别在于第一种方法执行的指令是:line 18: astore_1而第二种方法执行的指令是:line 16: atore_2这两条指令都是把returnAddress/引用类型存入局部变量。「所以说两种方法本质是一样的」都是执行invokevirtual #3来获取List中的对象引用。如果把楼主的例子改写成可以产生垃圾对象的例子:Object obj = null;for(int i=0; i<1000; i++) { obj = new Object();}和for(int i=0; i<1000; i++) { Object obj = new Object();}这两种方法,产生的垃圾对象也是可以等价的。每次循环一次,上一次循环的对象就失去了引用,变成了垃圾对象。〔呵呵,第二种方法还会多出一个垃圾对象。循环结束后,最后一次循环产生的新对象在第一种方法中还会被obj保持。〕:) 看了xiaohaiz(老土进城,两眼通红)的分析想起了list有过期引用的特例,就象stack一样垃圾收集器是不会对这里面的对象进行回收的list将自己管理这些对象最还在代码最后加上a=null; 两种方法差不多由于对象是在list产生时已经创建你用a=list.get(i);只是创建了一个指向list.get(i)的一个索引方法一只是声明一次然后不停的改变其指向的对象方法二每次声明一次,上一次声明的将在适当的时候被收回 TO fantasyCoder(牛仔+T恤):看你开始思路还算清楚,怎么最后来了一个画蛇添足,加上“a=null”做什么。:) to fantasyCoder(牛仔+T恤)何时启动垃圾收集器是没有办法控制的。即使你使用System.gc(),也仅仅是建议垃圾收集,而不是强迫垃圾收集。 承认错误,同意 xiaohaiz(老土进城,两眼通红)的看法。 问一个关于selenium在2003多用户下的问题 swing中如何从一个JFrame跳到另一个JFrame?急! 好多的视频教程 求最短距离算法的java版 java中的content-type是什么 讨论:声明类时,public final class A {}和 public static class A {}有什么不同 这么简单的一个函数,哪里会有错误呢?在线等,立刻给分 请大虾们帮忙,在线等! java反射简单问题 : 求解java2的家族关系? 困惑:主线程和从线程的相互中止或唤醒? 學習jdbc又有疑問.
当然是第二种!原因有两处:
(1) 两种做法对于垃圾收集的影响没有本质的差别,可以忽略之;
(2) 关键的原因:临时变量的作用域问题。临时变量的作用域应该最小化;由此可以引出一个关于循环的问题,就是for循环优于while循环:
<<
for(Iterator it=list.iterator(); it.hasNext(); ) {
Object each = it.next();
}
优于
Iterator it=list.iterator();
while( it.hasNext() ) {
Object each = it.next();
}
>>
在上面这两个例子中,Iterator it这个临时变量的作用域是不同的。
public static void main(String[] args){
System.out.println("Started:");
long time=System.currentTimeMillis();
//Integer a;
for(int i=0;i<100000000;i++){
Integer a=new Integer(i);
}
System.out.println("accomplished:"+String.valueOf(System.currentTimeMillis()-time));
}
}
运行时间前者5601ms
后者5518ms(不同机子上和不同时间运行都有可能不同)
两者基本上不分上下
方法一
public void M1();
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: goto 23
7: aload_0
8: getfield #2; //Field list:Ljava/util/Vector;
11: iload_2
12: invokevirtual #3; //Method java/util/Vector.get:(I)Ljava/lang/Object;
15: checkcast #4; //class ClassA
18: astore_1
19: nop
20: iinc 2, 1
23: iload_2
24: aload_0
25: getfield #2; //Field list:Ljava/util/Vector;
28: invokevirtual #5; //Method java/util/Vector.size:()I
31: if_icmplt 7
34: nop
35: return
方法二
public void M2();
Code:
0: iconst_0
1: istore_1
2: goto 21
5: aload_0
6: getfield #2; //Field list:Ljava/util/Vector;
9: iload_1
10: invokevirtual #3; //Method java/util/Vector.get:(I)Ljava/lang/Object;
13: checkcast #4; //class ClassA
16: astore_2
17: nop
18: iinc 1, 1
21: iload_1
22: aload_0
23: getfield #2; //Field list:Ljava/util/Vector;
26: invokevirtual #5; //Method java/util/Vector.size:()I
29: if_icmplt 5
32: nop
33: return}方法一的4-35行同方法二的2-33行基本一致,但方法一比方法二多了1-2行
0: aconst_null
1: astore_1
是用来初始化ClassA a = null的,所以方法一比方法二多一个初始化a的时间
如果少量调用这两个方法的话,区别不太大,但如果频繁调用这方法的话,还是方法二的性能稍微优越一点,
调用两个方法循环10000次结果如下
第一个4484
第二个4469
但是这个问题其实不在执行效率的区别之上,还是和之前提到的,是局部变量的作用域的问题。
不同意。
你为什么会认为第二种方法产生的垃圾对象会比第一种多?
在楼主的例子中,实际上两种方法都不会有什么垃圾对象。这些对象的引用始终被List保持,不会被垃圾收集。
其实看看第一种方法和第二种方法的区别,jjj3000(jjj3000) 反编译出来的字节码就可以展示清楚了。在循环体中除去循环控制语句不管,区别在于第一种方法执行的指令是:
line 18: astore_1
而第二种方法执行的指令是:
line 16: atore_2
这两条指令都是把returnAddress/引用类型存入局部变量。「所以说两种方法本质是一样的」都是执行invokevirtual #3来获取List中的对象引用。如果把楼主的例子改写成可以产生垃圾对象的例子:
Object obj = null;
for(int i=0; i<1000; i++) {
obj = new Object();
}
和
for(int i=0; i<1000; i++) {
Object obj = new Object();
}
这两种方法,产生的垃圾对象也是可以等价的。每次循环一次,上一次循环的对象就失去了引用,变成了垃圾对象。
〔呵呵,第二种方法还会多出一个垃圾对象。循环结束后,最后一次循环产生的新对象在第一种方法中还会被obj保持。〕
:)
想起了list有过期引用的特例,就象stack一样
垃圾收集器是不会对这里面的对象进行回收的
list将自己管理这些对象
最还在代码最后加上
a=null;
由于对象是在list产生时已经创建
你用a=list.get(i);只是创建了一个指向list.get(i)的一个索引
方法一只是声明一次然后不停的改变其指向的对象
方法二每次声明一次,上一次声明的将在适当的时候被收回
看你开始思路还算清楚,怎么最后来了一个画蛇添足,加上“a=null”做什么。:)
何时启动垃圾收集器是没有办法控制的。即使你使用System.gc(),也仅仅是建议垃圾收集,而不是强迫垃圾收集。