锁定老帖子 主题:java代码调优笔记(一)
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2011-10-28
包装类的内存占用是很恐怖的,它是基本类型内存占用的N倍(N>2),同时new一个对象也是性能的消耗。 我们再看看JDK对于Boolean.valueOf(boolean b)的实现: Boolean类提供了两个常量: public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); 而valueOf(boolean b)的内部实现是: return (b ? TRUE : FALSE); 因此用Boolean.valueOf(boolean b)代替new Boolean()既能节省空间,又能提高性能。 (2). 用Integer.valueOf(int i)代替new Integer() 和Boolean类似,java开发中使用Integer封装int的场合也非常多,并且通常用int表示的数值都非常小。SUN SDK中对Integer的实例化进行了优化,Integer类缓存了-128到127这256个状态的Integer,如果使用 Integer.valueOf(int i),传入的int范围正好在此内,就返回静态实例。这样如果我们使用Integer.valueOf代替new Integer的话也将大大降低内存的占用。 (3). 用StringBuffer的append方法代替"+"进行字符串相加。 这个已经被N多人说过N次了,这个就不多说了。 (4). 避免过深的类层次结构和过深的方法调用。 因为这两者都是非常占用内存的(特别是方法调用更是堆栈空间的消耗大户)。 (5). 变量只有在用到它的时候才定义和实例化。 这是初学者最容易犯的错,合理的使用变量,并且只有在用到它的时候才定义和实例化,能有效的避免内存空间和执行性能上的浪费,从而提高了代码的效率。 (6). 避免在循环体中声明创建对象,即使该对象占用内存空间不大。 这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误,例如下面的代码: for (int i = 0; i < 10000; ++i) { Object obj = new Object(); System.out.println("obj= " + obj); } 上面的做法会浪费较大的内存空间。正确的做法如下所示: Object obj = null; for (int i = 0; i < 10000; ++i) { obj = new Object(); System.out.println("obj= "+ obj); } 采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象引用,浪费大量的内存空间,而且增大了垃圾回收的负荷。因此在循环体中声明创建对象的编写方式应该尽量避免。 (7). 如果if判断中多个条件用'||'或者'&&'连接,请将出现频率最高的条件放在表达式最前面。 这个小技巧往往能有效的提高程序的性能,尤其是当if判断放在循环体里面时,效果更明显。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-10-28
最后修改:2011-10-28
(6). 避免在循环体中声明创建对象,即使该对象占用内存空间不大。
这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误,例如下面的代码: for (int i = 0; i < 10000; ++i) { Object obj = new Object(); System.out.println("obj= " + obj); } 上面的做法会浪费较大的内存空间。正确的做法如下所示: Object obj = null; for (int i = 0; i < 10000; ++i) { obj = new Object(); System.out.println("obj= "+ obj); } 采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象引用,浪费大量的内存空间,而且增大了垃圾回收的负荷。因此在循环体中声明创建对象的编写方式应该尽量避免。 我一直都是采用的第二种编写方式,没有原因,只是非常讨厌第一种编写方式,我也是后来才知道第一种方式不好的! |
|
返回顶楼 | |
发表时间:2011-10-28
yjydmlh 写道 (6). 避免在循环体中声明创建对象,即使该对象占用内存空间不大。
这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误,例如下面的代码: for (int i = 0; i < 10000; ++i) { Object obj = new Object(); System.out.println("obj= " + obj); } 上面的做法会浪费较大的内存空间。正确的做法如下所示: Object obj = null; for (int i = 0; i < 10000; ++i) { obj = new Object(); System.out.println("obj= "+ obj); } 采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象引用,浪费大量的内存空间,而且增大了垃圾回收的负荷。因此在循环体中声明创建对象的编写方式应该尽量避免。 我一直都是采用的第二种编写方式,没有原因,只是非常讨厌第一种编写方式,我也是后来才知道第一种方式不好的! 呵呵,无论是上面那种还是下面这种,堆内分配的对象都没有减少.至于说增加gc负担就更无从谈起了. 但是第二种方法会增加栈当中的引用数量.比如这个例子来说就是增加 9999个引用 ,差不多是40000byte ,也就是40K的开销.. |
|
返回顶楼 | |
发表时间:2011-10-28
哈哈,一看到这种帖子,我就忍不住回复一下..如果觉得我有说错的,可以一起探讨..
(3)可能是大家的误解还是怎么,其实在java里面,压根没必要做这个优化.因为在编译阶段,编译器自动帮我们把+转换成StringBuilder.append .大家可以直接用试试.直接用+好拼装字符串,然后用javap -c 看看对应的方法内容. (4)类层次过深和方法调用过深,对程序可读性的影响,远远大于对性能的影响..我的理解是,这个应该不算性能提高的范畴.因为jdk6的-xss默认是1M,只要不是递归,不可能操作这个数的.. (6)第六条,上面已经说了.. |
|
返回顶楼 | |
发表时间:2011-10-28
chenjingbo 写道 yjydmlh 写道 (6). 避免在循环体中声明创建对象,即使该对象占用内存空间不大。
这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误,例如下面的代码: for (int i = 0; i < 10000; ++i) { Object obj = new Object(); System.out.println("obj= " + obj); } 上面的做法会浪费较大的内存空间。正确的做法如下所示: Object obj = null; for (int i = 0; i < 10000; ++i) { obj = new Object(); System.out.println("obj= "+ obj); } 采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象引用,浪费大量的内存空间,而且增大了垃圾回收的负荷。因此在循环体中声明创建对象的编写方式应该尽量避免。 我一直都是采用的第二种编写方式,没有原因,只是非常讨厌第一种编写方式,我也是后来才知道第一种方式不好的! 呵呵,无论是上面那种还是下面这种,堆内分配的对象都没有减少.至于说增加gc负担就更无从谈起了. 但是第二种方法会增加栈当中的引用数量.比如这个例子来说就是增加 9999个引用 ,差不多是40000byte ,也就是40K的开销.. 请问chenjingbo大大,第二中写法增加的是哪个引用的数量?真的增加了引用的数量么?增加的引用是存放在哪里的? |
|
返回顶楼 | |
发表时间:2011-10-28
Object obj = null;
for (int i = 0; i < 10000; ++i) { obj = new Object(); System.out.println("obj= "+ obj); } 只有一个引用obj ,循环一次换一个指向 但是 还是多创建了 9999个对象 ,如果没有引用回报回收 |
|
返回顶楼 | |
发表时间:2011-10-29
在新的 java 版本中,string 用+和stringbuffer的append效率应该是差不多的。
java 5 以后引入了更高效的StringBuilder(非线程安全),API类似于StringBuffer。 |
|
返回顶楼 | |
发表时间:2011-10-29
wad12302 写道 Object obj = null;
for (int i = 0; i < 10000; ++i) { obj = new Object(); System.out.println("obj= "+ obj); } 只有一个引用obj ,循环一次换一个指向 但是 还是多创建了 9999个对象 ,如果没有引用回报回收 如果 System.out.println("obj= "+ obj); 的操作换成是 list.add(obj);//添加进List 想像这样的后果。 |
|
返回顶楼 | |
发表时间:2011-10-29
hantsy 写道 wad12302 写道 Object obj = null;
for (int i = 0; i < 10000; ++i) { obj = new Object(); System.out.println("obj= "+ obj); } 只有一个引用obj ,循环一次换一个指向 但是 还是多创建了 9999个对象 ,如果没有引用回报回收 如果 System.out.println("obj= "+ obj); 的操作换成是 list.add(obj);//添加进List 想像这样的后果。 额.后果很雷同. |
|
返回顶楼 | |
发表时间:2011-10-29
chenjingbo 写道 yjydmlh 写道 (6). 避免在循环体中声明创建对象,即使该对象占用内存空间不大。
这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误,例如下面的代码: for (int i = 0; i < 10000; ++i) { Object obj = new Object(); System.out.println("obj= " + obj); } 上面的做法会浪费较大的内存空间。正确的做法如下所示: Object obj = null; for (int i = 0; i < 10000; ++i) { obj = new Object(); System.out.println("obj= "+ obj); } 采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象引用,浪费大量的内存空间,而且增大了垃圾回收的负荷。因此在循环体中声明创建对象的编写方式应该尽量避免。 我一直都是采用的第二种编写方式,没有原因,只是非常讨厌第一种编写方式,我也是后来才知道第一种方式不好的! 呵呵,无论是上面那种还是下面这种,堆内分配的对象都没有减少.至于说增加gc负担就更无从谈起了. 但是第二种方法会增加栈当中的引用数量.比如这个例子来说就是增加 9999个引用 ,差不多是40000byte ,也就是40K的开销.. 你也不想想一个项目里会有多少个这样的循环?2000个好算少的? |
|
返回顶楼 | |