性能主题

Java性能优化技巧

  本文综合了各种Java性能优化的研究成果,涵盖从JDK到Java集合使用、场景用例到和工具。

  1. 如果在静态构造器中有繁重的计算,也就是耗费CPU的逻辑代码,请检查其运行时间是否过度?如果是,将这些逻辑迁移到另外一个单独的帮助类中。Static constructor code is not JIT-optimized in a lot of cases

  2. 在进行byte[]作为String的构造参数时,需要将byte数组的一部分做个复制拷贝,否则,构造器会为整个原始缓冲做一个临时拷贝;试图避免不必要的内存分配,因为在内存使用超过1G+以上时会影响程序的性能,Inefficient byte[] to String constructor

  3. 变量对于大多数程序是非常有用的,因为它们缩短了代码,但是当变量的所有成员已经确认是不变的常量,那么使用预编译的数组替代。Java varargs performance issues:

  4. 尽可能使用StringBuilder替代StringBuffer。Primitive types to String conversion and String concatenation

  5. 使用闪存SSD替代传统的硬盘HDD,这样你可以将你的应用程序从I/O-bound转变到CPU-bound,这对于设计到read/write流操作特别有用;现代操作系统都是在后台写数据,不会堵塞你的应用,你的写操作只有在操作系统写入磁盘的速度慢于你的应用产生数据的速度时,才会堵塞你的写操作请求:I/O bound algorithms: SSD vs HDD

  6. 如果你的内存中有字符串或带有String字段的对象的大量集合,在某些情况下,字少10%场景,这些字符串实际上可能会转换为基本类型的值,你可以使用Object字段替代你的String字段,使用其提供的pack/unpack方法在字符串和对象之间来回转换,这样节省内存。如果你不将字符串转换为基本类型,可以考虑将字符串转为UTF-8的byte[],可以随时将byte[]转回原始字符串。String packing part 2: converting Strings to any other objects

  7. 如果有大量重复的字符串,使用String.intern() 减少内存损耗,提高性能:Reducing memory usage with String.intern()String.intern in Java 6, 7 and 8 - part 3String.intern in Java 6, 7 and 8 - multithreaded access

  8. 尝试使用Google protobuf 或类似编码技术编码你整数数据,特别是这些数据值很小的情况下,这样你会得到数据量大幅度减小后导致的低CPU损耗,能够帮助你提高每个时间单元中存储或读取更多消息数量。

  9. 如果使用 array list/set/map 时,其key或值是基本类型,那么使用Trove的 maps/sets替代JDK maps/sets,可以节省大量内存。Trove library: using primitive collections for performance

  10. 当你的应用堆heap大小超过32G时, JVM会切换到64位的对象引用,意味着你的应用已经结束了占用更少Heap空间的阶段。 Going over Xmx32G heap boundary means you will have less memory available

  11. 如果你使用内部类,缺省使用静态的内部类;如果你使用一堆小的集合Collection,那么试试使用 java.util.Collections.empty*/singleton*方法实现小集合的内存高效率存储;使用BitSet替代boolean的arrays/lists或一系列integer整数类型,bit set是内存和CPU缓存都很友好。A few more memory saving techniques in Java

  12. 不要在多线程中共享一个 java.util.Random实例,将其包装在ThreadLocal中,Java7中使用java.util.concurrent.ThreadLocalRandom替代java.util.Random 。

  13.  如果你希望有快速的Base64编码器,使用Java 8的 java.util.Base64 

  14. 不要使用exception ,每个exception 启动需要1毫秒:Creating an exception in Java is very slow

  15. 如果你使用:

if ( !set.contains( key ) )
{
    set.add( key );
    //some extra code here
}

直接使用add更快:

if ( set.add( key ) ){
    //same extra code could be added here
}

同样,contains+remove可以被remove直接替代。

  16. 如果要使用压缩,考虑使用LZ4Performance of various general compression algorithms - some of them are unbelievably fast!

  17. 使用ByteBuffer替代 ByteArrayOutputStream。java.io.ByteArrayOutputStream

  18. 如果你希望计算几天这样的短天数,那么基于int/long进行手工实现会更快些。JSR 310 - Java 8 Date/Time library performance (as well as Joda Time 2.3 and j.u.Calendar)

  19.  使用Matcher 和 Pattern 替代String.matches, split, replaceAll, replaceFirst等方法。Regexp-related methods of String

  20. 如果你希望有一个快速的LinkedList代码实现,考虑下面规则:

  • 使用ArrayDeque实现基于队列queue-based的算法
  • 使用LinkedList的ListIterator
  • 避免使用任何LinkedList方法接受或返回集合中元素的索引。
  • 再次检查是否有理由使用LinkedList

  21. 如果使用ArrayList,考虑下面规则:

  • 将元素追加到集合尾部。
  • 也从尾部移除元素
  • 避免contains, indexOf 和remove(Object) 方法
  • 避免更多的removeAll和retainAll 方法
  • 使用subList(int, int).clear() 来清除集合中的一部分。

 

  22.Java 8中使用G1垃圾回收机制时,使用减少字符串重复配置: -XX:+UseG1GC -XX:+UseStringDeduplication。

 

Java集合Collection使用比较与总结