锁定老帖子 主题:一个clone的效率问题
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2006-12-15
deafwolf 写道 ahuaxuan 写道 deafwolf 写道 抛出异常的爱 写道 你加一句system.gc()
以防内存使用优化区别.... jvm 对new有很多变态的优化方式 这样的话,是不是就等于说在正常情况下用new的内存开销比clone大? 如果使用那些优化,clone就没有意义了? 应该是jvm对new操作的优化造成的结果,但是这个和垃圾收集并没有什么关系,这个操作计算的是创建所用的时间,创建对象之后,这些对象何去何从并不重要。 上面有人说clone没有意义,这也是不对的,clone方法的意义在于得到一摸一样的两个对象,这种需求显然不是很多吧,难道有人做过得到10w个一摸一样的对象这种需求吗,我想jvm设计人员在设计的时候肯定也想到了这一点,显然clone就是用在得到一个或几个一摸一样的对象才有用,如果真是10w个这种需求当然要用new,因为用clone不但效率低,而且代码也会变复杂(看看楼主的代码就知道了),由此可以得出: 1,如果需要少量一摸一样的对象,应该使用clone方法。 2,如果需要大量一摸一样的对象,应该使用new方法,而且可以肯定的是jvm对new操作有相当强度的优化。 楼主把两个针对不同目的的操作(new,clone)放在一起对比的结果也说明了他们确实是针对不同需求的 如果是为了得到一模一样的对象,完全可以用new的方法 class Test{ //property public Test(){} public Test(Test test){ this.XXX=test.getXXX(); //... } //setter&getter } 如果仅仅是获得几个相同的对象,直接用new应该更省事,毕竟就那几个对象,不差这点时间,对吧? 用new怎么会更省事呢?? 用new是很费事的一件事,如果只是影子拷贝用new费事还不能得到很好的体现,但是如果是深拷贝呢,用new要多出很多代码来,不信你试一下,即使只是影子拷贝的情况,上面带参数的构造方法也是有很多代码吧,比如说一个域对象有30个字段的话,这时候用clone就会非常简单了,就一行代码。但是如果有需求要10w个这样一摸一样的域对象,那么用new快一点,但是用new确实麻烦(如果真有这个需求,这点麻烦还是值得的) |
|
返回顶楼 | |
发表时间:2006-12-15
teleping 写道 这样说来,clone并没有效率上的优势,仅仅是在操作上带来方便了?
在复制少量对象时clone要比new快呀,而且实现深拷贝很简单,显然clone不适合很大量的复制(这种需求我做到现在还没有见过,如果出现这种需求,用new吧,呵呵) |
|
返回顶楼 | |
发表时间:2006-12-15
例子的用的空构造函数
而clone函数函数有代码 会不会clone函数里面的代码影响了效率?? |
|
返回顶楼 | |
发表时间:2006-12-15
teleping 写道 数组赋值的用意我还不太清楚,还望提点
![]() int count=10000; Object[] objs=new Object[count]; for(int i=0;i<count;i++){ objs[i]=new XXX();//or clone();just for preventing garbage collector from destroy the object right now } ... |
|
返回顶楼 | |
发表时间:2006-12-15
楼主看的资料是什么时候的? 看到你的clone 方法,里面有try catch …… 据说try catch 比 new 还要慢一点,呵呵。
|
|
返回顶楼 | |
发表时间:2006-12-15
呵呵,刚又看了一下Object的源代码,发现 clone 方法前面有个 native 关键词,顿时明白了很多。
所以做了以下这个试验 修改了楼主的部分源代码,把 new 的代价增大了。 class A implements Cloneable { String abc = add("t"); String def = add("f"); void m1() { System.out.println(abc); } private String add(String string) { String s = ""; for (int i = 0; i < 1000; i++) { s += string; } return s; } void m2() { System.out.println(def); } public Object clone() { Object obj = null; try { obj = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return obj; } private static A a = new A(); public static A getInstance() { return (A) a.clone(); } } class CloneTest { public static void main(String[] args) throws Exception { long times = 100; long time1 = 0; long time2 = 0; time1 = testNew(times); time2 = testClone(times); System.out.println(times + " 次 new() 用时[共,平均]:" + time1 + "," + time1 / times); System.err.println(times + " 次 clone() 用时[共,平均]:" + time2 + "," + time2 / times); } public static long testNew(long times) { long start = System.currentTimeMillis(); for (long i = 0; i < times; i++) { new A(); } long end = System.currentTimeMillis(); return end - start; } public static long testClone(long times) throws CloneNotSupportedException { long start = System.currentTimeMillis(); for (long i = 0; i < times; i++) { A.getInstance(); } long end = System.currentTimeMillis(); return end - start; } } 测试多次,结果如下: 100 次 new() 用时[共,平均]:593,5 100 次 clone() 用时[共,平均]:0,0 100 次 new() 用时[共,平均]:640,6 100 次 clone() 用时[共,平均]:0,0 100 次 new() 用时[共,平均]:609,6 100 次 clone() 用时[共,平均]:0,0 100 次 new() 用时[共,平均]:609,6 100 次 clone() 用时[共,平均]:0,0 这下明白了,上面那个例子,不是clone效率多高,而是new代价太大。当new代价不大的时候,new的效率会高过clone。 |
|
返回顶楼 | |
发表时间:2006-12-16
我按我的想法试验了一下,发现如果保持对象的引用不即时释放的话,new和clone的时间基本上是一样的。clone会稍慢一些。
10000 次 new() 用时[共,平均]:0,0 10000 次 clone() 用时[共,平均]:0,0 100000 次 new() 用时[共,平均]:47,0 100000 次 clone() 用时[共,平均]:47,0 1000000 次 new() 用时[共,平均]:484,0 1000000 次 clone() 用时[共,平均]:516,0 package test; class A implements Cloneable { String abc = "ttttttttttttttttttttttttttttt"; String def = "sssssssssssssssssssssssssssss"; void m1() { System.out.println(abc); } void m2() { System.out.println(def); } public Object clone() { Object obj = null; try { obj = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return obj; } private static A a = new A(); public static A getInstance() { return (A) a.clone(); } } public class TestClone { public static void main(String[] args) throws Exception { int times = 1000000; long time1 = 0; long time2 = 0; time1 = testNew(times); time2 = testClone(times); System.out.println(times + " 次 new() 用时[共,平均]:" + time1 + "," + time1 / times); System.err.println(times + " 次 clone() 用时[共,平均]:" + time2 + "," + time2 / times); } public static long testNew(int times) { Object[] objs=new Object[times]; long start = System.currentTimeMillis(); for (int i = 0; i < times; i++) { objs[i]=new A(); } long end = System.currentTimeMillis(); return end - start; } public static long testClone(int times) { Object[] objs=new Object[times]; long start = System.currentTimeMillis(); for (int i = 0; i < times; i++) { objs[i]=A.getInstance(); } long end = System.currentTimeMillis(); return end - start; } } 另外我发现一个奇怪的事情, 将main方法中的两句话对调一下, time1 = testNew(times); time2 = testClone(times); 结果如下: 1000000 次 new() 用时[共,平均]:265,0 1000000 次 clone() 用时[共,平均]:719,0 看来先执行的吃亏。 然后每次执行一个测试,即new或clone,结果如下: 1000000 次 new() 用时[共,平均]:468,0 1000000 次 clone() 用时[共,平均]:719,0 这样分别运行的测试比较准,没有先后秩序的相关性。 |
|
返回顶楼 | |
发表时间:2006-12-23
xiaoych 写道 呵呵,刚又看了一下Object的源代码,发现 clone 方法前面有个 native 关键词,顿时明白了很多。
所以做了以下这个试验 修改了楼主的部分源代码,把 new 的代价增大了。 ...... 这下明白了,上面那个例子,不是clone效率多高,而是new代价太大。当new代价不大的时候,new的效率会高过clone。 明白些了,当执行new时会进行比较耗资源的操作时,用clone避免new,就可以提高效率; 如果new中根本做的事情很少,clone就体现不了优势,相反,有可能会有额外的耗费。 谢谢各位! |
|
返回顶楼 | |
发表时间:2006-12-23
我没有注意过讨论clone和new效率的文献, 不过就我的理解, 只有单层继承层次的类对象上clone有可能占到的便宜不大, 谁有空可以试试, 增加几个继承层次, 比如 A->B->C->D, 这样用 D类 来做相同的测试, 结果应该又会不一样了. 因为有层层调用构造方法的开销, 所以继承层次越多, new应该就会比clone越慢.
不过也有可能JVM对空构造方法进行优化, 但是到1.5的HotSpot为止应该还不会扭转这个趋势, 新出的JDK1.6没有测试过, 不太清楚. |
|
返回顶楼 | |
发表时间:2006-12-23
测试不是很正确,
1、应该分别run clone和new,不应该在一块。 2、clone的优势主要在很占内存的数据类型中使用 代码应该为: (由于比较懒,所以用注释方法测试不同的)。 class A implements Cloneable { String abc = "ttttttttttttttttttttttttttttt"; String def = "sssssssssssssssssssssssssssss"; String strs []=new String [100]; void m1() { System.out.println(abc); } void m2() { System.out.println(def); } public Object clone() { Object obj = null; try { obj = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return obj; } private static A a = new A(); public static A getInstance() { return (A) a.clone(); } } public class CloneTest { public static void main(String[] args) throws Exception { long times = 1000000; // long time1 = 0;//test new long time2 = 0;//test clone // time1 = testNew(times);//test new time2 = testClone(times);//test clone // System.out.println(times + " 次 new() 用时[共,平均]:" + time1 + "," + time1 / times);//test new System.err.println(times + " 次 clone() 用时[共,平均]:" + time2 + "," + time2 / times);//test clone } public static long testNew(long times) { long start = System.currentTimeMillis(); for (long i = 0; i < times; i++) { new A(); } long end = System.currentTimeMillis(); return end - start; } public static long testClone(long times) { long start = System.currentTimeMillis(); for (long i = 0; i < times; i++) { A.getInstance(); } long end = System.currentTimeMillis(); return end - start; } } 结果如下: Clone:1000000 次 clone() 用时[共,平均]:312,0 new:1000000 次 new() 用时[共,平均]:484,0 其他可以换生成对象的多少来试一下。 |
|
返回顶楼 | |