论坛首页 Java企业应用论坛

[表示怀疑]什么样的优化能让Java程序性能提高2.5倍?

浏览 39191 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2004-11-26  
个人觉得,性能优化应该是优化瓶颈部分的算法,而不是解决“循环new对象”这个问题,这个应该算是改错,而不是优化!我相信任何一个公司/项目的java编程规约上应该有相关的描述,“循环new对象”违反规约了,必须改正。
0 请登录后投票
   发表时间:2004-11-26  
所定,建议大家去ibmdw,找一个基于效能的系列看看。
吹牛和吵架都要有个限度,目前的讨论没有任何学术和技术意义。

http://www-106.ibm.com/developerworks/views/java/articles.jsp?sort_order=desc&expand=&sort_by=Date&show_abstract=true&view_by=Search&search_by=performance%3A
看看这个系列,对大家有好处。
0 请登录后投票
   发表时间:2004-11-26  
我想可能 flyingbugs 的程序有很多 String 操作吧?
String 操作不当,的确很影响性能的。把循环 new String 的操作,用 StringBuffer 来做,效率应该会提高不少。

当然,我搞 C/C++ 的,对于 java 不太懂,不能写个程序证明一下。
0 请登录后投票
   发表时间:2004-11-26  
在循环里不能随意new对象有什么依据啊?是自已想当然吧。
怕占内存吗,在循环里的对象一般是使用范围就在所在函数内,这种对象
你再new也不会消耗内存的。
0 请登录后投票
   发表时间:2004-11-26  
jkit 写道
个人觉得,性能优化应该是优化瓶颈部分的算法,而不是解决“循环new对象”这个问题,这个应该算是改错,而不是优化!我相信任何一个公司/项目的java编程规约上应该有相关的描述,“循环new对象”违反规约了,必须改正。

没错,一般情况“循环new对象”这个问题在java程序员中是不存在的,并且是在对性能要求比较高的系统中。你们以前做这个系统的人是java新手吧
0 请登录后投票
   发表时间:2004-11-26  
关于异常处理目前大多数人都认为 Rod Johnson 的看说是正确的

一些异常本质上是次要的返回代码(它通常指示违反业务规则),而一些异常则是“发生某种可怕错误”(例如数据库连接失败)的变种。Johnson 提倡对于第一种类别的异常(可选的返回代码)使用检查型异常,而对于后者使用运行时异常

“违反业务规则的”
0 请登录后投票
   发表时间:2004-12-04  
To gigix:
内存操作占60%的应用一点也不奇怪,不要说60%,占90%以上的也很多,不同的领域有不同的要求,不要以为Mis就是全部。对于计算密集形的程序来说,对于关键算法,不要说多几层少几层,就是多一个方法调用都要仔细掂量,一个方法调用就意味着好几个堆栈操作,每秒50M的调用使用多少时钟周期?

还用,提高2.5倍一点也不是什么奇怪的事情,更不要以为原来写程序的人是新手低手。就象你所说的,1.3的GC比1.1的GC性能要高很多,那是不是就是说写1.1GC的人是个低手?我想答案是否定的。94年写GC的人是个高手,但当时Java没大规模应用,他可能并没有想到GC的瓶颈在哪里,01年写1.3(or1.4)GC的人可能水平和94年的人差不多,但他有大量的应用作基础,再加上积累和时间的推移,他才写出性能优异的GC,在某些场合,远远超过2.5倍。

算法对性能的提高2.5倍只是个很平常的数字。比如bubble sort和quick sort.在quick sort发明之前,谁又能知道sort可以这么快呢?
0 请登录后投票
   发表时间:2004-12-04  
本来我已经不想参加这个讨论,因为口水已经太多了。但是看来我还是要说几句才可以。
内存操作占90%的程序是什么程序呢?我想大家自己心里都会有这个概念,在这个地方讨论没有什么意思。
对于不同的领域应用当然会有区别,但是我不知道为什么要用java去完成复杂的算法。而且如果这个算法那么要紧,对于性能的要求那么严格,我看不出你为什么一定要使用java直接来做这个事情。写几个java的汇编并不是那么困难的事情,而使用其他语言完成复杂的算法也是很好的选择。

其实讨论来讨论去,根本上还是要在技术上进行。你看不惯就看不惯,没有什么人需要满足你的喜好。高手和低手都可以发表自己的看法,当然这是要建立在诚实的基础上。不要去评论别人的水平,免得你自己受到评论。但是一个刚学习java不久的人就说怎么怎么可以把别人的代码优化的多么多么好,这样的事情你和一百个人说,会有90个骂你在吹牛。另外5个不说也是在怀疑,而另外5个根本就没有听。这段话不是仅仅针对一个人,而是为所有参加这个讨论的人说的。
0 请登录后投票
   发表时间:2004-12-04  
gigix 写道
EJB容器提供pool,仅仅是因为从前的JVM GC效率太低,不得不采用的权宜之计。在Java 1.3之后的VM里面,GC效率的提升已经使EJB容器的instance pooling变成了一个反模式。详情请参见J2EE without EJB第12章,或请教dlee同志。

确实是这样,如果不大清楚 GC 的分代机制,建议读一下相关的文档。我只简单说一下。所有现代的 JVM 都实现了分代的 GC。就是把内存的堆空间分成了两部分:“年轻一代”和“老一代”。刚刚 new 出来的对象都在“年轻一代”中。GC 过程分成两种类型,频率很高的小收集和频率很低的大收集。小收集只扫描“年轻一代”存储区,释放掉所有没有被引用的对象。而经过若干次小收集都没有被释放的对象则会被转移“老一代”存储区中。大收集执行频率很低,因为需要扫描所有的堆空间,所以消耗的时间也是比较长的。但是如果理解了 GC 的这种分代机制,把代码写好,对象仅仅在需要使用时才创建,不再需要后立即释放,那么这样的对象永远不会进入“老一代”中,而现代 JVM 由于采用了高效的算法,对“年轻一代”所做的小收集的效率是非常高的。关于分代的垃圾收集,可以看看 developerWorks 上 Brian Goetz 写的一系列文章:http://www-900.ibm.com/developerWorks/cn/java/j-jtp10283/
http://www-900.ibm.com/developerWorks/cn/java/j-jtp11253/

分代的 GC 是在 JVM 1.3 以后的版本才出现的。EJB 由于孕育在 JVM 1.1 的年代,那个时候 GC 的效率比较低,于是设计者认为 pooling 资源对象对于提高性能是非常关键的。这个看法在当时确实是正确的,但是现在已经是 JVM 1.5 的时代了,因此 EJB 一成不变的 pooling 方法按照现在的观点看来是完全过时了。实际上现在效率最高的方法就是在用的时候直接 new 一个对象,用完了就立即释放。资源对象的 pooling 现在不再是必须的了,甚至不适当的 pooling 还会对分代 GC 的性能造成损害。其实现在很多场合下只有数据库连接是必须要 pooling 的资源对象。pooling 对于一个容器来说,完全不是其最主要的功能之一。即使容器不提供,我也可以自己写一个,或者使用开源的产品(Jakarta Commons、PoolMan,etc.)。关于资源对象的 pooling,Rod Johnson 在 without EJB 第 12 章有很详细的讨论。

对于提高性能的追求要有一个度,不能太片面。如果性能的优化大幅度降低了代码的可读性(产生了非常复杂和难以理解的代码),那么我宁愿不去做这种性能优化。因为以后理解这些代码将花费了我们一个程序员大量的时间,从成本上来说是不划算的。
一段写的很差的代码,造成了性能的下降。我们需要做的第一件事不应该是直接加以修改以提高性能,而应该是先对这一段代码进行重构,消除掉其中大部分的臭味。经过良好重构的代码的性能是不会很低的,而且重构后得到了更好的代码结构,对于以后做性能优化提供了非常好的基础(可以更加方便地做性能优化)。我们可以找出一段写的非常差的代码,我来做重构,flyingbugs 来直接做性能优化,我们来看一下最后的结果性能究竟能差多少。
如何做好代码重构,建议去认真读一读侯捷和 gigix 共同翻译的《重构》。

flyingbugs 写道
1.在关键的地方 少使用Exception,特别是不要使用Exception来判断流称。
2.尽量减少不必要的new操作(注意,是不必要的,不要为了方便,而随便new一把)。
3.同步!!尽力避免同步的发生,除非在没有办法的办法情况下。 很多时候,同步是可以通过适当的数据结构和算法调整来实现的。
4.对于瓶颈发生的地方,仔细考虑软硬件环境,必要的时候,需要修改算法,用自己的特定的算法来改造。

1、2、4 我基本上同意。对于 3 我要纠正一下,很多时候影响性能的不是同步本身,而是是否存在对锁的竞争和是否有效避免了竞争,所以不要简单地对使用同步畏之如虎。同步如果能用好,很多时候对于性能的影响是不大的。这个观点 Rod Johnson 在 without EJB 第 12 章中同样有详细的讨论。

说点题外话,这个主题虽然很长,但是大多没有多少内容(感觉不过瘾),还陷入了不必要的口水战。其实就是一个以前在这里讨论的很充分的老问题:究竟是 OOP 重要还是算法重要?我的看法是,OOP 解决的主要还是软件结构方面的问题,算法解决的是软件细部的问题,两者都是非常重要的。一个好的程序员必须同时是 OOP 和算法的高手。但是在大多数开发工作中(例如一般的 MIS、ERP 应用,复杂性更多的发生在业务逻辑上而不是在算法本身上面),OOP 的成分更多一些。即使 OOP 用熟了(设计模式查都不用查直接写出来),算法、数据结构仍然是软件开发的基础。OOP 也可以看作是一种高级的数据结构,当然它除了数据本身的组织,还包括可以在数据之上执行的操作的组织。程序 = 数据结构 + 算法,这个等式大家都不会忘记吧?那么我们有什么必要单纯强调一方而忽视另一方呢? Java 把一些常用的数据结构和算法都封装起来了(直接封装在 Java 核心类库中),提供了一个 OO 的 API 让开发人员访问,所以开发人员自己去实现一些基本算法的场合就比较少了(当然 C++ 也有封装的非常好的 STL)。以至于 Martin Fowler 都感叹我们在 OO 方面走了这么远以后是不是把学校里面学习的那些数据结构、算法都忘掉了。但是现在必须由应用的开发人员(是做普通的应用,不是做底层类库的开发)自己去实现复杂算法的场合确实并不多。如果有这样的场合,那就只好再把这些东西捡回来了,而如果要用到更加复杂的算法,就只好去啃《计算机程序设计艺术》或者专业的论文了。当然如果有封装的很好的开源类库可以直接使用,那就最省事了。100% OO 仅仅是一个审美上的选择(我现在也更喜欢采用 OO 方式封装的很好的组件,因为使用起来确实更方便),而并不是什么清规戒律。
0 请登录后投票
   发表时间:2004-12-05  
dlee 写道
我的看法是,OOP 解决的主要还是软件结构方面的问题,算法解决的是软件细部的问题,两者都是非常重要的。一个好的程序员必须同时是 OOP 和算法的高手。

这句话我深表同意。好的程序员=OOP+算法。两者也不是对立的,很多时候两都也是相辅相成,如果构架混乱,算法也往往不会清晰有效。因为构架和数据模型都是建立在对业务的深刻理解和抽象的基础之上。

dlee 写道
分代的 GC 是在 JVM 1.3 以后的版本才出现的。EJB 由于孕育在 JVM 1.1 的年代,那个时候 GC 的效率比较低,于是设计者认为 pooling 资源对象对于提高性能是非常关键的。这个看法在当时确实是正确的,但是现在已经是 JVM 1.5 的时代了,因此 EJB 一成不变的 pooling 方法按照现在的观点看来是完全过时了。实际上现在效率最高的方法就是在用的时候直接 new 一个对象,用完了就立即释放。资源对象的 pooling 现在不再是必须的了,甚至不适当的 pooling 还会对分代 GC 的性能造成损害。其实现在很多场合下只有数据库连接是必须要 pooling 的资源对象。pooling 对于一个容器来说,完全不是其最主要的功能之一。

补充一下,对于现代的GC来说,轻量级的对象是完全没有必要pooling的;对于重量级的对象,除了数据库连接之外,还有创建时涉及IO操作,或创建涉及大量计算等的对象,一般需要综合的权衡一下。在很多场合,缓存还是提高性能的最有效的手段。

dlee 写道
对于提高性能的追求要有一个度,不能太片面。如果性能的优化大幅度降低了代码的可读性(产生了非常复杂和难以理解的代码),那么我宁愿不去做这种性能优化。因为以后理解这些代码将花费了我们一个程序员大量的时间,从成本上来说是不划算的。
一段写的很差的代码,造成了性能的下降。我们需要做的第一件事不应该是直接加以修改以提高性能,而应该是先对这一段代码进行重构,消除掉其中大部分的臭味。经过良好重构的代码的性能是不会很低的,而且重构后得到了更好的代码结构,对于以后做性能优化提供了非常好的基础(可以更加方便地做性能优化)。

如里提高性能是以代码的可读性为代价的,除非是性能的提高到了一个我无法拒绝的水平,99.99%的情况我是不会去做这种优化的,这也是我不是很赞同对于一些关键算法改为C或汇编去实现的主要原因(还有部分是跨平台的原因)。虚拟机技术一直在发展,虽然我对java号称达到C的性能水平表示怀疑,对达到80%的水准我想大家都可以接受,为了20%的性能要牺牲代码的可读性和跨平台的优势,对我来说是得不偿失。

dlee 写道
1、2、4 我基本上同意。对于 3 我要纠正一下,很多时候影响性能的不是同步本身,而是是否存在对锁的竞争和是否有效避免了竞争,所以不要简单地对使用同步畏之如虎。同步如果能用好,很多时候对于性能的影响是不大的。这个观点 Rod Johnson 在 without EJB 第 12 章中同样有详细的讨论。

尽量少用同步,深层次的原因正如你如说的,是怕同步用不好,而不是同步本身不好。我一向以为,能用简单的方法完成,就绝不用复杂的。能用单线程完成的,就绝不用多线程。
0 请登录后投票
论坛首页 Java企业应用版

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