您的位置:首页 > 编程语言 > Java开发

java性能优化概要

2016-08-31 16:34 288 查看
<div id="article_content" class="article_content">

<p style="">下面是参考网络资源总结的一些在Java编程中尽可能要做到的一些地方。</p>

<p style="">  1. 尽量在合适的场合使用单例</p>

<p style="">  使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面:</p>

<p style="">  第一,控制资源的使用,通过线程同步来控制资源的并发访问;</p>

<p style="">  第二,控制实例的产生,以达到节约资源的目的;</p>

<p style="">  第三,控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。</p>

<p style="">  2. 尽量避免随意使用静态变量</p>

<p style="">  要知道,当某个对象被定义为stataic变量所引用,那么gc通常是不会回收这个对象所占有的内存,如</p>

<p style="">  Java代码</p>

<p style="">  public class A{</p>

<p style="">  static B b = new B();</p>

<p style="">  }</p>

<p style="">  此时静态变量b的生命周期与A类同步,如果A类不会卸载,那么b对象会常驻内存,直到程序终止。</p>

<p style="">  3. 尽量避免过多过常的创建Java对象</p>

<p style="">  尽量避免在经常调用的方法,循环中new对象,由于系统不仅要花费时间来创建对象,而且还要花时间对这些对象进行垃圾回收和处理,在我们可以控制的范围内,最大限度的重用对象,最好能用基本的数据类型或数组来替代对象。</p>

<p style="">  4. 尽量使用final修饰符</p>

<p style="">  带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String.为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%.</p>

<p style="">  5. 尽量使用局部变量</p>

<p style="">  调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。</p>

<p style="">  6. 尽量处理好包装类型和基本类型两者的使用场所</p>

<p style="">  虽然包装类型和基本类型在使用过程中是可以相互转换,但它们两者所产生的内存区域是完全不同的,基本类型数据产生和处理都在栈中处理,包装类型是对象,是在堆中产生实例。</p>

<p style="">  在集合类对象,有对象方面需要的处理适用包装类型,其他的处理提倡使用基本类型。</p>

<p style="">  7. 慎用synchronized,尽量减小synchronize的方法</p>

<p style="">  都知道,实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。synchronize方法被调用时,直接会把当前对象锁 了,在方法执行完之前其他线程无法调用当前对象的其他方法。所以synchronize的方法尽量小,并且应尽量使用方法同步代替代码块同步。</p>

<p style="">  8. 尽量使用StringBuilder和StringBuffer进行字符串连接</p>

<p style="">  这个就不多讲了。</p>

<p style="">  9. 尽量不要使用finalize方法</p>

<p style="">  实际上,将资源清理放在finalize方法中完成是非常不好的选择,由于GC的工作量很大,尤其是回收Young代内存时,大都会引起应用程序暂停,所以再选择使用finalize方法进行资源清理,会导致GC负担更大,程序运行效率更差。</p>

<p style="">  10. 尽量使用基本数据类型代替对象</p>

<p style="">  String str = "hello";</p>

<p style="">  上面这种方式会创建一个"hello"字符串,而且JVM的字符缓存池还会缓存这个字符串;</p>

<p style="">  String str = new String("hello");</p>

<p style="">  此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o</p>

<p style="">  11. 单线程应尽量使用HashMap、ArrayList</p>

<p style="">  HashTable、Vector等使用了同步机制,降低了性能。</p>

<p style="">  12. 尽量合理的创建HashMap</p>

<p style="">  当你要创建一个比较大的hashMap时,充分利用另一个构造函数</p>

<p style="">  public HashMap(int initialCapacity, float loadFactor)</p>

<p style="">  避免HashMap多次进行了hash重构,扩容是一件很耗费性能的事,在默认中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能准确的估计你所需要的最佳大小,同样的Hashtable,Vectors也是一样的道理。</p>

<p style="">  13. 尽量减少对变量的重复计算</p>

<p style="">  如</p>

<p style="">  for(int i=0;i</p>

<p style="">  应该改为</p>

<p style="">  for(int i=0,len=list.size();i</p>

<p style="">  并且在循环中应该避免使用复杂的表达式,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。</p>

<p style="">  14. 尽量避免不必要的创建</p>

<p style="">  如</p>

<p style="">  A a = new A();</p>

<p style="">  if(i==1){list.add(a);}</p>

<p style="">  应该改为</p>

<p style="">  if(i==1){</p>

<p style="">  A a = new A();</p>

<p style="">  list.add(a);}</p>

<p style="">  15. 尽量在finally块中释放资源</p>

<p style="">  程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。</p>

<p style="">  16. 尽量使用移位来代替'a/b'的操作</p>

<p style="">  "/"是一个代价很高的操作,使用移位的操作将会更快和更有效</p>

<p style="">  如</p>

<p style="">  int num = a / 4;</p>

<p style="">  int num = a / 8;</p>

<p style="">  应该改为</p>

<p style="">  int num = a 》 2;</p>

<p style="">  int num = a 》 3;</p>

<p style="">  但注意的是使用移位应添加注释,因为移位操作不直观,比较难理解</p>

<p style="">  17.尽量使用移位来代替'a*b'的操作</p>

<p style="">  同样的,对于'*'操作,使用移位的操作将会更快和更有效</p>

<p style="">  如</p>

<p style="">  int num = a * 4;</p>

<p style="">  int num = a * 8;</p>

<p style="">  应该改为</p>

<p style="">  int num = a 《 2;</p>

<p style="">  int num = a 《 3;</p>

<p style="">  18. 尽量确定StringBuffer的容量</p>

<p style="">  StringBuffer 的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再 丢弃旧的数组。在大多数情况下,你可以在创建 StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。</p>

<p style="">  如:StringBuffer buffer = new StringBuffer(1000);</p>

<p style="">  19. 尽量早释放无用对象的引用</p>

<p style="">  大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null.</p>

<p style="">  例如:</p>

<p style="">  Java代码</p>

<p style="">  Public void test(){</p>

<p style="">  Object obj = new Object();</p>

<p style="">  ……</p>

<p style="">  Obj=null;</p>

<p style="">  }</p>

<p style="">  上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:</p>

<p style="">  Java代码</p>

<p style="">  Public void test(){</p>

<p style="">  Object obj = new Object();</p>

<p style="">  ……</p>

<p style="">  Obj=null;</p>

<p style="">  //执行耗时,耗内存操作;或调用耗时,耗内存的方法</p>

<p style="">  ……</p>

<p style="">  }</p>

<p style="">  这时候就有必要将obj赋值为null,可以尽早的释放对Object对象的引用。</p>

<p style="">  20. 尽量避免使用二维数组</p>

<p style="">  二维数据占用的内存空间比一维数组多得多,大概10倍以上。</p>

<p style="">  21. 尽量避免使用split</p>

<p style="">  除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需 要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。</p>

<p style="">  22. ArrayList & LinkedList</p>

<p style="">  一 个是线性表,一个是链表,一句话,随机查询尽量使用ArrayList,ArrayList优于LinkedList,LinkedList还要移动指 针,添加删除的操作LinkedList优于ArrayList,ArrayList还要移动数据,不过这是理论性分析,事实未必如此,重要的是理解好2 者得数据结构,对症下药。</p>

<p style="">  23. 尽量使用System.arraycopy ()代替通过来循环复制数组</p>

<p style="">  System.arraycopy() 要比通过循环来复制数组快的多</p>

<p style="">  24. 尽量缓存经常使用的对象</p>

<p style="">  尽可能将经常使用的对象进行缓存,可以使用数组,或HashMap的容器来进行缓存,但这种方式可能导致系统占用过多的缓存,性能下降,推荐可以使用一些第三方的开源工具,如EhCache,Oscache进行缓存,他们基本都实现了FIFO/FLU等缓存算法。</p>

<p style="">  25. 尽量避免非常大的内存分配</p>

<p style="">  有时候问题不是由当时的堆状态造成的,而是因为分配失败造成的。分配的内存块都必须是连续的,而随着堆越来越满,找到较大的连续块越来越困难。</p>

<p style="">  26. 慎用异常</p>

<p style="">  当创建一个异常时,需要收集一个栈跟踪(stack track),这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照,正是这一部分开销很大。当需要创建一个 Exception 时,JVM 不得不说:先别动,我想就您现在的样子存一份快照,所以暂时停止入栈和出栈操作。栈跟踪不只包含运行时栈中的一两个元素,而是包含这个栈中的每一个元素。</p>

<p style="">  如 果您创建一个 Exception ,就得付出代价。好在捕获异常开销不大,因此可以使用 try-catch 将核心内容包起来。从技术上讲,您甚至可以随意地抛出异常,而不用花费很大的代价。招致性能损失的并不是 throw 操作--尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。幸运的是,好的编程习惯已教会我们,不应该不管三七二十一就 抛出异常。异常是为异常的情况而设计的,使用时也应该牢记这一原则。</p>

<p style="">  (1)。 用Boolean.valueOf(boolean b)代替new Boolean()</p>

<p style="">  包装类的内存占用是很恐怖的,它是基本类型内存占用的N倍(N>2),同时new一个对象也是性能的消耗。</p>

<p style="">  我们再看看JDK对于Boolean.valueOf(boolean b)的实现:</p>

<p style="">  Boolean类提供了两个常量:</p>

<p style="">  Java代码</p>

<p style="">  public static final Boolean TRUE = new Boolean(true);</p>

<p style="">  public static final Boolean FALSE = new Boolean(false);</p>

<p style="">  而valueOf(boolean b)的内部实现是:</p>

<p style="">  Java代码</p>

<p style="">  return (b ? TRUE : FALSE);</p>

<p style="">  因此用Boolean.valueOf(boolean b)代替new Boolean()既能节省空间,又能提高性能。</p>

<p style="">  (2)。 用Integer.valueOf(int i)代替new Integer()</p>

<p style="">  和Boolean类似,java开发中使用Integer封装int的场合也非常多,并且通常用int表示的数值都非常小。SUN SDK中对Integer的实例化进行了优化,Integer类缓存了-128到127这256个状态的Integer,如果使用 Integer.valueOf(int i),传入的int范围正好在此内,就返回静态实例。这样如果我们使用Integer.valueOf代替new Integer的话也将大大降低内存的占用。</p>

<p style="">  (3)。 用StringBuffer的append方法代替"+"进行字符串相加。</p>

<p style="">  这个已经被N多人说过N次了,这个就不多说了。</p>

<p style="">  (4)。 避免过深的类层次结构和过深的方法调用。</p>

<p style="">  因为这两者都是非常占用内存的(特别是方法调用更是堆栈空间的消耗大户)。</p>

<p style="">  (5)。 变量只有在用到它的时候才定义和实例化。</p>

<p style="">  这是初学者最容易犯的错,合理的使用变量,并且只有在用到它的时候才定义和实例化,能有效的避免内存空间和执行性能上的浪费,从而提高了代码的效率。</p>

<p style="">  (6)。 避免在循环体中声明创建对象,即使该对象占用内存空间不大。</p>

<p style="">  这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误,例如下面的代码:</p>

<p style="">  Java代码</p>

<p style="">  for (int i = 0; i < 10000; ++i) {</p>

<p style="">  Object obj = new Object();</p>

<p style="">  System.out.println("obj= " + obj);</p>

<p style="">  }</p>

<p style="">  上面的做法会浪费较大的内存空间。正确的做法如下所示:</p>

<p style="">  Java代码</p>

<p style="">  Object obj = null;</p>

<p style="">  for (int i = 0; i < 10000; ++i) {</p>

<p style="">  obj = new Object();</p>

<p style="">  System.out.println("obj= "+ obj);</p>

<p style="">  }</p>

<p style="">  采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象引用,浪费大量的内存空间,而且增大了垃圾回收的负荷。因此在循环体中声明创建对象的编写方式应该尽量避免。</p>

<p style="">  (7)。 如果if判断中多个条件用'||'或者'&&'连接,请将出现频率最高的条件放在表达式最前面。</p>

<p style="">  这个小技巧往往能有效的提高程序的性能,尤其是当if判断放在循环体里面时,效果更明显。</p>

<p style="">  1.JVM管理两种类型的内存:堆内存(heap),栈内存(stack),堆内在主要用来存储程序在运行时创建或实例化的对象与变量。而栈内存则是用来存储程序代码中声明为静态(static)(或非静态)的方法。</p>

<p style="">  2.JVM中对象的生命周期,创建阶段,应用阶段,不可视阶段,不可到达阶段,可收集阶段,终结阶段,释放阶段</p>

<p style="">  3.避免在循环体中创建对象,即使该对象点用内存空间不大。</p>

<p style="">  for(int i=0;i<10000;++i){</p>

<p style="">  Object obj = new Object();</p>

<p style="">  System.out.println("obj="+obj);</p>

<p style="">  }</p>

<p style="">  应改成</p>

<p style="">  Object obj = null;</p>

<p style="">  for(int i=0;i<10000;++i){</p>

<p style="">  obj = new Object();</p>

<p style="">  System.out.println("obj="+obj);</p>

<p style="">  }</p>

<p style="">  4.软引用的主要特点是具有较强的引用功能。只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收。它可以用于实现一些常用资源的缓存,实现Cache的功能</p>

<p style="">  A a = new A();</p>

<p style="">  SoftReference sr = new SoftReference(a);</p>

<p style="">  a = null;</p>

<p style="">  if(sr !=null){</p>

<p style="">  a = sr.get();</p>

<p style="">  }else{</p>

<p style="">  a = new A();</p>

<p style="">  sr = new SoftReference(a);</p>

<p style="">  }</p>

<p style="">  5.弱引用对象与Soft引用对象最大不同就在于:GC在进行回收时,需要通过算法检查是否回收Soft引用对象,而对于Weak引用对象,GC总是进行回收。</p>

<p style="">  A a = new A();</p>

<p style="">  WeakReference wr = new WeakReference(a);</p>

<p style="">  a = null;</p>

<p style="">  if(sr !=null){</p>

<p style="">  a = wr.get();</p>

<p style="">  }else{</p>

<p style="">  a = new A();</p>

<p style="">  wr = new WeakReference(a);</p>

<p style="">  }</p>

<p style="">  6.共享静态变量存储空间</p>

<p style="">  7.有时候我们为了提高系统性能,避免重复耗时的操作,希望能够重用一些创建完成的对象,利用对象池实现。类似JDBC连接池。</p>

<p style="">  8.瞬间值,序列化对象大变量时,如果此大变量又没有用途,则使用transient声明,不序列化此变量。同时网络传输中也不传输。</p>

<p style="">  9.不要提前创建对象</p>

<p style="">  void f(){</p>

<p style="">  int i;</p>

<p style="">  A a = new A();</p>

<p style="">  if(…){</p>

<p style="">  a.showMessage();</p>

<p style="">  }</p>

<p style="">  }</p>

<p style="">  改成</p>

<p style="">  void f(){</p>

<p style="">  int i;</p>

<p style="">  A a = null;</p>

<p style="">  if(…){</p>

<p style="">  //用到时才实例化</p>

<p style="">  a = new A();</p>

<p style="">  a.showMessage();</p>

<p style="">  }</p>

<p style="">  }</p>

<p style="">  10 .(1)最基本的建议就是尽早释放无用对象的引用</p>

<p style="">  A a = new A();</p>

<p style="">  a = null; //当使用对象a之后主动将其设置为空</p>

<p style="">  (2)尽量少用finalize函数。</p>

<p style="">  (3) 如果需要使用经常用到的图片展,可以使用软引用。</p>

<p style="">  (4) 注意集合数据类型,包括数组,树等数据,这些数据结构对GC来说,回收更为复杂,</p>

<p style="">  (5) 尽量避免在类的默认构造器中创建,初始化大量的对象,防止在调用其自类的构造器时造成不必要的内存资源浪费。</p>

<p style="">  (6) 尽量避免强制系统做垃圾内存回收。</p>

<p style="">  (7) 尽量避免显式申请数组空间。</p>

<p style="">  (8) 尽量在合适的场景下使用对象池技术以提高系统性能,缩减系统内存开销。</p>

<p style="">  11.当做数组拷贝操作时,采用System.arraycopy()方法完成拷贝操作要比采用循环的办法完成数组拷贝操作效率高</p>

<p style="">  12. 尽量避免在循环体中调用方法,因为方法调用是比较昂贵的。</p>

<p style="">  13. 尽量避免在循环体中使用try-catch 块,最好在循环体外使用try--catch块以提高系统性能。</p>

<p style="">  14. 在多重循环中,如果有可能,尽量将最长的循环放在最内层,最短的循环放在最外层,以减少循环层间的变换次数。</p>

<p style="">  15. 在需要线程安全的情况下,使用List list = Collections.synchronizedList(new ArrayList());</p>

<p style="">  16. 如果预知长度,就设置ArrayList的长度。</p>

<p style="">  17. ArrayList 与 LinkedList 选择,熟悉底层的实现原理,选择适当的容器。</p>

<p style="">  18. 字符串累加采用StringBuffer.</p>

<p style="">  19. 系统I/O优化,采用缓冲和压缩技术。优化性能。</p>

<p style="">  20. 避免在类在构造器的初始化其他类</p>

<p style="">  21 尽量避免在构造中对静态变量做赋值操作</p>

<p style="">  22. 不要在类的构造器中创建类的实例</p>

<p style="">  23. 组合优化继承</p>

<p style="">  24. 最好通过Class.forname() 动态的装载类</p>

<p style="">  25. JSP优化,采用out 对象中的print方法代替println()方法</p>

<p style="">  26 .采用ServletOutputStream 对象代替JSPWriter对象</p>

<p style="">  27. 采用适当的值初始化out 对象缓冲区的大小</p>

<p style="">  28. 尽量采用forward()方法重定向新的JSP</p>

<p style="">  29. 利用线程池技术处理客户请求</p>

<p style="">  30.Servlet优化</p>

<p style="">  (1) 通过init()方法来缓存一些静态数据以提高应用性能。</p>

<p style="">  (2) 用print() 方法取代println()方法。</p>

<p style="">  (3) 用ServletOutputStream 取代 PrintWriter.</p>

<p style="">  (4) 尽量缩小同步代码数量</p>

<p style="">  31. 改善Servlet应用性能的方法</p>

<p style="">  (1)不要使用SingleThreadModel</p>

<p style="">  (2)使用线程池ThreadPool</p>

<p style="">  32. EJB优化</p>

<p style="">  实体EJB:</p>

<p style="">  (1)实体EJB中常用数据缓存与释放</p>

<p style="">  (2)采用延迟加载的方式装载关联数据</p>

<p style="">  (3)尽可能地应用CMP类型实体EJB</p>

<p style="">  (4)直接采用JDBC技术处理大型数据</p>

<p style="">  33. 优化JDBC连接</p>

<p style="">  (1)设置合适的预取行值</p>

<p style="">  (2)采用连接池技术</p>

<p style="">  (3)全合理应用事务</p>

<p style="">  (4)选择合适的事务隔离层与及时关闭连接对象</p>

<p style="">  34. PreparedStatemetn只编译解析一次,而Statement每次都编译解析。</p>

<p style="">  35. 尽可能地做批处理更新</p>

<p style="">  36. 通过采用合适的getXXX方法提高系统性能</p>

<p style="">  37. 采用设计模式。</p>

<br>

   

</div>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: