论坛首页 Java企业应用论坛

关于性能优化

浏览 40003 次
精华帖 (2) :: 良好帖 (10) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2010-11-17   最后修改:2010-11-17
ouchxp 写道

JDK自己已经有优化了. 不合理的优化反而会降低效率
比如字符串常量拼接
String str ="aaa" + "bbb" +"ccc" + "ddd";

StringBuilder sb = new StringBuilder();
sb.append("aaa");
sb.append("bbb");
sb.append("ccc");
sb.append("ddd");
String str = sb.toString();

哪种效率高? 答案是第一种. 对于新手来说想优化很容易适得其反.
反编译看一下就知道为什么了.


我们项目经理不让用第一种
0 请登录后投票
   发表时间:2010-11-17  
ironsabre 写道
flysnowxf 写道
ironsabre 写道
flysnowxf 写道
汗,这是很基础的概念了。
百度百科:http://baike.baidu.com/view/714962.htm

引用
当以前分配的一片内存不再需要使用或无法访问时,但是却并没有释放它,那么对于该进程来说,会因此导致总可用内存的减少,这时就出现了内存泄漏。


再说一次,向集合里一直加东西不删除,这个不叫内存泄漏。


那是你的理解了。我的理解是,分配了内存,但这些内存不再被使用,比如过期了、没用了,但又没有去删除,造成内存占用越来越多。HashMap的使用就容易出现这个问题。


哎。你这个没过期,也有用。你可以通过HashMap取出来值的,这怎么能叫泄漏呢?
我现在总是你,如果你向cache里放了100个对象,永远keep住,如果我应用程序经常来访问它,叫不叫泄漏?
如果我应用程序再也不来访问它,叫不叫泄漏?
按你的理解,第一种不叫,第二种叫。可这两种没有区别。我不可能用由第三方来判断我自己是不是泄漏,明白吗?

下面这个Stack,在被别人用的时候,可能会引起泄漏。你先找找看哪行会出总是。然后再理解一下跟你这个有什么区别。
import java.util.Arrays;
import java.util.EmptyStackException;

public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;

public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}

public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}

public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}

/**
* Ensure space for at least one more element, roughly doubling the capacity
* each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}


你这个封装Object[]的Stack跟封装HashMap的Cache有什么区别?
内存泄漏是指存在无法释放的无用引用,从这点来说,HashMap里面的内容也是内存泄漏。
0 请登录后投票
   发表时间:2010-11-17  
bitray 写道
赞成2楼和三楼的观点。虽然可能平时大家注意的并不是真正的性能瓶颈。但是如果不重视自己代码的书写规范和简洁,那么写出来的代码就是隐藏的瓶颈,是你最后很难优化出来的东西。有习惯的程序员用stringbuffer和stringbuilder,但是如果是不重视,就会有人用+连接,在多处,一定数据量的情况下,都可能产生隐含问题等

jdk6的字符串拼接内部是用Stringbuilder实现的,现在在sb上纠缠是不明智的。大多情况下+的性能比StringBuilder高
0 请登录后投票
   发表时间:2010-11-17  
抛出异常的爱 写道
kingkan 写道
在下的一点愚见:性能优化在于平时开发习惯的积累,新手因为知识深度面的缺乏而想不到程序高效的写法很正常,老手开发一般写出来的代码都是比较高效的,所以在开发过程中对于过于考虑性能优化是没多大必要,关键是开发前考虑的吞吐量,系统框架在I/O上瓶颈,还有热路径等,进入开发后就是代码工作啦,测试,Beta,Release,上线,维护。

不要犯错就差不多了
设计的好就不太需要考虑优化的事.
必竟j2ee又不是c
我平时很少进行coding时考虑性能问题.


呵呵,老手一般在潜意识里面已经coding优化了,写出来的代码通常都没问题,剩下就交给QA吧
0 请登录后投票
   发表时间:2010-11-17  
蔡华江 写道
ironsabre 写道
flysnowxf 写道
ironsabre 写道
flysnowxf 写道
汗,这是很基础的概念了。
百度百科:http://baike.baidu.com/view/714962.htm

引用
当以前分配的一片内存不再需要使用或无法访问时,但是却并没有释放它,那么对于该进程来说,会因此导致总可用内存的减少,这时就出现了内存泄漏。


再说一次,向集合里一直加东西不删除,这个不叫内存泄漏。


那是你的理解了。我的理解是,分配了内存,但这些内存不再被使用,比如过期了、没用了,但又没有去删除,造成内存占用越来越多。HashMap的使用就容易出现这个问题。


哎。你这个没过期,也有用。你可以通过HashMap取出来值的,这怎么能叫泄漏呢?
我现在总是你,如果你向cache里放了100个对象,永远keep住,如果我应用程序经常来访问它,叫不叫泄漏?
如果我应用程序再也不来访问它,叫不叫泄漏?
按你的理解,第一种不叫,第二种叫。可这两种没有区别。我不可能用由第三方来判断我自己是不是泄漏,明白吗?

下面这个Stack,在被别人用的时候,可能会引起泄漏。你先找找看哪行会出总是。然后再理解一下跟你这个有什么区别。
import java.util.Arrays;
import java.util.EmptyStackException;

public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;

public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}

public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}

public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}

/**
* Ensure space for at least one more element, roughly doubling the capacity
* each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}


你这个封装Object[]的Stack跟封装HashMap的Cache有什么区别?
内存泄漏是指存在无法释放的无用引用,从这点来说,HashMap里面的内容也是内存泄漏。


HashMap里的内容你仍然可以自由的存取的,这不叫泄漏,你觉得内存不够用了,你可以去删除掉一些。这完全可以自己控制的,这叫什么泄漏??那按你这个说法,只要向容器里放对象就是泄漏了??

我们现在再看这个Stack类,我把这个Stack类打成一个jar包,然后我提供给你用,你用上面这个Stack作为你的容器,你push一万次,再pop一万次,你的Stack的size已经是0了,但是这一万个对象仍然无法放掉(前提当然是Stack本身要被keep住)。你会有一些内存你已经永远无法使用了,而且你已经没有任何能力去放掉它了(不包括回收到Stack本身)。
看得懂区别了吗??
0 请登录后投票
   发表时间:2010-11-17  
ironsabre 写道
蔡华江 写道
ironsabre 写道
flysnowxf 写道
ironsabre 写道
flysnowxf 写道
汗,这是很基础的概念了。
百度百科:http://baike.baidu.com/view/714962.htm

引用
当以前分配的一片内存不再需要使用或无法访问时,但是却并没有释放它,那么对于该进程来说,会因此导致总可用内存的减少,这时就出现了内存泄漏。


再说一次,向集合里一直加东西不删除,这个不叫内存泄漏。


那是你的理解了。我的理解是,分配了内存,但这些内存不再被使用,比如过期了、没用了,但又没有去删除,造成内存占用越来越多。HashMap的使用就容易出现这个问题。


哎。你这个没过期,也有用。你可以通过HashMap取出来值的,这怎么能叫泄漏呢?
我现在总是你,如果你向cache里放了100个对象,永远keep住,如果我应用程序经常来访问它,叫不叫泄漏?
如果我应用程序再也不来访问它,叫不叫泄漏?
按你的理解,第一种不叫,第二种叫。可这两种没有区别。我不可能用由第三方来判断我自己是不是泄漏,明白吗?

下面这个Stack,在被别人用的时候,可能会引起泄漏。你先找找看哪行会出总是。然后再理解一下跟你这个有什么区别。
import java.util.Arrays;
import java.util.EmptyStackException;

public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;

public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}

public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}

public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}

/**
* Ensure space for at least one more element, roughly doubling the capacity
* each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}


你这个封装Object[]的Stack跟封装HashMap的Cache有什么区别?
内存泄漏是指存在无法释放的无用引用,从这点来说,HashMap里面的内容也是内存泄漏。


HashMap里的内容你仍然可以自由的存取的,这不叫泄漏,你觉得内存不够用了,你可以去删除掉一些。这完全可以自己控制的,这叫什么泄漏??那按你这个说法,只要向容器里放对象就是泄漏了??

我们现在再看这个Stack类,我把这个Stack类打成一个jar包,然后我提供给你用,你用上面这个Stack作为你的容器,你push一万次,再pop一万次,你的Stack的size已经是0了,但是这一万个对象仍然无法放掉(前提当然是Stack本身要被keep住)。你会有一些内存你已经永远无法使用了,而且你已经没有任何能力去放掉它了(不包括回收到Stack本身)。
看得懂区别了吗??

是你没看懂我的意思。我指的是“封装了HashMap"的Cache。
你如果能拿到Stack中Object[]的引用,你一样可以对数组进行操作。
如果你拿不到HashMap的引用,你一样无法对数组进行操作。
所以问题并不是hashMap本身。
其次,就算你能拿到HashMap本身,我也认为这是内存泄漏。请注意,"内存泄漏是指存在无法释放的无用引用"。
Java最大特色在于内存的自动释放。
Object a = new Object();
。。。
a = null;
显然,a是释放了的,至少程序员的本意是要释放a的,但是由于集合中保存了另一个a的引用(这个总是很隐蔽的),导致a的内存并没有释放,这不是溢出,这是泄漏。
0 请登录后投票
   发表时间:2010-11-17  
象string和stringbuffer这些应该是养成一个编程习惯,单纯的String str = "a"+"b"+"c"换成stringbuffer意义也不大,但是如果通过一个循环来拼一个string,那stringbuffer还有点作用(有两年多没用java了,新的java1.6有没有优化就不清楚了)。其实性能问题更多的是由设计引起的,比如要获取一个列表的记录总数怎样实现(select count(0) from tablename吗?)、怎样实现翻页这些都会存在性能问题。 如果从纯技术角度,那优化DB的回报是最高的,比如对查询语句建索引(建索引提升一两个数量级的速度是很正常的)。一般的性能问题通常发生在DB服务器,应用服务器只要不内存泄漏的话,一般不会有什么太大问题的。
0 请登录后投票
   发表时间:2010-11-17  
dsjt 写道
ouchxp 写道

JDK自己已经有优化了. 不合理的优化反而会降低效率
比如字符串常量拼接
String str ="aaa" + "bbb" +"ccc" + "ddd";

StringBuilder sb = new StringBuilder();
sb.append("aaa");
sb.append("bbb");
sb.append("ccc");
sb.append("ddd");
String str = sb.toString();

哪种效率高? 答案是第一种. 对于新手来说想优化很容易适得其反.
反编译看一下就知道为什么了.


我们项目经理不让用第一种

如果你们的JDK版本在1.4或以下的话还说得过去.
如果是1.5或以上.
你完全可以和他提出来.你写一段测试代码给他看.执行效率有很明显的对比
反编译Class给他看.JDK已经做好优化了.自己的优化不仅多余,反而降低了执行效率
0 请登录后投票
   发表时间:2010-11-17  
指尖帝 写道
bitray 写道
赞成2楼和三楼的观点。虽然可能平时大家注意的并不是真正的性能瓶颈。但是如果不重视自己代码的书写规范和简洁,那么写出来的代码就是隐藏的瓶颈,是你最后很难优化出来的东西。有习惯的程序员用stringbuffer和stringbuilder,但是如果是不重视,就会有人用+连接,在多处,一定数据量的情况下,都可能产生隐含问题等

jdk6的字符串拼接内部是用Stringbuilder实现的,现在在sb上纠缠是不明智的。大多情况下+的性能比StringBuilder高

+1
尤其是字符串常量拼接+的性能要大大好于StringBuilder
0 请登录后投票
   发表时间:2010-11-17  
指尖帝 写道
bitray 写道
赞成2楼和三楼的观点。虽然可能平时大家注意的并不是真正的性能瓶颈。但是如果不重视自己代码的书写规范和简洁,那么写出来的代码就是隐藏的瓶颈,是你最后很难优化出来的东西。有习惯的程序员用stringbuffer和stringbuilder,但是如果是不重视,就会有人用+连接,在多处,一定数据量的情况下,都可能产生隐含问题等

jdk6的字符串拼接内部是用Stringbuilder实现的,现在在sb上纠缠是不明智的。大多情况下+的性能比StringBuilder高


变量拼接还是很有问题的。JDK 1.6下。
testString cost =453 mils
testStringBuilder cost =0 mils


public static void main(String[] args) {
long t1 = System.currentTimeMillis();
String str1 = "";
for (int i = 0; i < 20000; i++) {
str1 = str1 + "a";
}
long t2 = System.currentTimeMillis();
System.out.println("testString cost =" + (t2 - t1) + " mils");

StringBuilder sb = new StringBuilder("");
long t3 = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
sb.append("a");
}
long t4 = System.currentTimeMillis();
System.out.println("testStringBuilder cost =" + (t4 - t3) + " mils");

}
0 请登录后投票
论坛首页 Java企业应用版

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