论坛首页 Java企业应用论坛

一个clone的效率问题

浏览 11821 次
精华帖 (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确实麻烦(如果真有这个需求,这点麻烦还是值得的)
0 请登录后投票
   发表时间:2006-12-15  
teleping 写道
这样说来,clone并没有效率上的优势,仅仅是在操作上带来方便了?


在复制少量对象时clone要比new快呀,而且实现深拷贝很简单,显然clone不适合很大量的复制(这种需求我做到现在还没有见过,如果出现这种需求,用new吧,呵呵)
0 请登录后投票
   发表时间:2006-12-15  
例子的用的空构造函数
而clone函数函数有代码
会不会clone函数里面的代码影响了效率??
0 请登录后投票
   发表时间: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
}
...
0 请登录后投票
   发表时间:2006-12-15  
楼主看的资料是什么时候的? 看到你的clone 方法,里面有try catch …… 据说try catch 比 new 还要慢一点,呵呵。
0 请登录后投票
   发表时间: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。
0 请登录后投票
   发表时间: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
这样分别运行的测试比较准,没有先后秩序的相关性。
0 请登录后投票
   发表时间:2006-12-23  
xiaoych 写道
呵呵,刚又看了一下Object的源代码,发现 clone 方法前面有个 native 关键词,顿时明白了很多。

所以做了以下这个试验

修改了楼主的部分源代码,把 new 的代价增大了。

......

这下明白了,上面那个例子,不是clone效率多高,而是new代价太大。当new代价不大的时候,new的效率会高过clone。



明白些了,当执行new时会进行比较耗资源的操作时,用clone避免new,就可以提高效率;
如果new中根本做的事情很少,clone就体现不了优势,相反,有可能会有额外的耗费。

谢谢各位!
0 请登录后投票
   发表时间:2006-12-23  
我没有注意过讨论clone和new效率的文献, 不过就我的理解, 只有单层继承层次的类对象上clone有可能占到的便宜不大, 谁有空可以试试, 增加几个继承层次, 比如  A->B->C->D, 这样用 D类 来做相同的测试, 结果应该又会不一样了. 因为有层层调用构造方法的开销, 所以继承层次越多, new应该就会比clone越慢.
不过也有可能JVM对空构造方法进行优化, 但是到1.5的HotSpot为止应该还不会扭转这个趋势, 新出的JDK1.6没有测试过, 不太清楚.
0 请登录后投票
   发表时间: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

其他可以换生成对象的多少来试一下。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics