(翻译www.java-performance.com)提高Java程序性能--JDK篇(六)

在Java中创建一个Exception对象非常慢,为什么?怎么避免?
1. 永远不要把抛Exception异常用来作为函数的返回值或者处理很可能发生的事件,因为创建一个Exception的代价在昂贵了,几乎一个Exception需要1us。
2. 有3种方法避免Exception的代价:重构代码不要使用它们;缓存一个Exception的实例,然后重用它;覆盖Exception类的fillInStackTrace方法。
3. 当有大量的字符串要转换成数,而待转换的字符串又有很多是无法转换成功的,这种情况下就不要用相关的parse*/valueOf函数进行转换,还是老老实实的自己写转换函数。


怎样尽量减少日志代码的性能损失?
1.写日志时,如里要记录的数据需要大量计算,可以将这个计算过程放在一个if语句中,用Logger.isLoggable判断,在真的需要写日志时才真正进行计算,或者将计算过程放在对象的toString函数中。
2.写日志时永远不要自己调用对象的toString方法,日志框架会自动帮你调用的,所以在传参时直接将对象传入即可。
3.不要将格式字符串与待记录的对象混连在一起,这可能会给恶意用户可乘之机。(我的理解是要么待记录对象全以参数的形式放到格式字符串中,要么直接与普通字符串进行连接。以slf4j为例:
应该:logger.info("this is {}, this is {}", obj1, obj2);
不该:logger.info("this is {}, this is " + obj2, obj1);


从性能角度来比较几种比较出名的BASE64编解码工具
1.如果你要找一个又快又可靠的Base64编解码工具,不用到JDK以外去找,java8中的java.util.Base64就可以。还有一个是从java6开始提供的javax.xml.bind.DatatypeConverter,这两个都是又快又可靠,而且不用担心整数溢出。
2.在4个第三方编解码工具中有2个比较出众:MiGBase64和IHarder。不幸的是如果你需要一次处理几百M的数据,只有google的guava可以允许最大一次解码2G数据(MiGBase64最大支持360MB,IHarder最大支持720M)。不幸的是guava不支持从byte[]到byte[]的编码。
3.如果字符串非常大,而且字符集charset是多字节字符集时不要调用String.getBytes(Charset)函数,这可能会产生整数溢出相关的异常。


multimap与内存泄漏相关的问题
1. 正如你所看到的,在实现多级Map(Map套Map)时容易产生内存泄漏。在操作外层Map时要特别小心地将读和写操作分开。
2. 像Google Guava, java 8, scala这些新的框架和语言提供了一些更方便的语法或者集合以避免在使用多级Map时产生内存泄漏。


并发编程中的Random的使用
1.任何情况下都不要将一个java.util.Random实例让多个线程共用,用ThreadLocal来包装它。
2.在Java7以后在任何情况下都用ava.util.concurrent.ThreadLocalRandom代替java.util.Random,它可以向后兼容已存在的代码,并且在内部实现方式花费更小代价。


java不同版本字符集的编解码性能
1.使用字符编码时宁愿用国家化的编码(比如:windows-1252,Shift_JIS)而不要用UTF-8。因为国家化的编码的二进制形式更紧凑,在编解码速度上更快。
2.在java7和java8中ISO-8859-1比 US-ASCII更快,如果没有特别的原因需要用 US-ASCII那么就用ISO-8859-1。
3.你可以写一个很快的函数将以US-ASCII/ISO-8859-1编码的String转换成byte[]类型,但就是没有java自带的解码器快。(意思就是将US-ASCII/ISO-8859-1从String转换成btye[]就用java自己的解码函数。)


探讨java的switch语句中用字符串作条件
1.String switch in Java 7 is implemented using a fixed size map with a number of slots close to 20. 这意味着在大部分情况下,随便用以字符串作条件的switch语句而不用担心性能。正如你所见,在case条件小于100的情况下用字符串作条件的switch语句,它的性能与手动实现一个映射是完全一样的。
2.当作为条件的各字符串在数量不是很多,且各字符串长度完全不一样或者一样的情况很少,用String.equals/equalsIgnoreCase来比较比使用switch语句更好。因为在String.equals/equalsIgnoreCase函数中,在比较内容前会先比较两个字符串的长度。


原文

Creating an exception in Java is very slow: why it is too expensive to create exceptions in Java and how can you avoid those costs: java.lang.Throwablejava.lang.Exception,java.lang.RuntimeExceptionsun.misc.BASE64Decoderjava.lang.NumberFormatException:

Tags: low latencyhigh throughputCPU optimization.

  • Never use exceptions as return code replacement or for any likely to happen events. Creating an exception is too expensive - the cost starts from approximately 1 microsecond per exception.
  • There are 3 ways to avoid exception costs: refactor your code not to use them; cache an instance of exception or override its fillInStackTrace method.
  • Avoid using any Number subclass parse*/valueOf methods if you call them for each piece of your data and you expect a lot of non-numerical data. Parse such values manually for top performance.

Java logging performance pitfalls: how to lose as little as possible performance while writing log messages: java.util.logging.Loggerjava.util.logging.Handler,java.util.logging.Formatterjava.text.MessageFormat:

Tags: low latencyhigh throughputCPU optimizationlogging.

  • If you make expensive calculations while preparing data for log messages, either use Logger.isLoggable and do all data preparation inside or write an object which does all calculations in its toString method.
  • Never call Object.toString method in order to obtain a log message argument - just pass an original object. Logging framework will call toString method on your object.
  • Do not mix format string concatenation with log arguments - malicious concatenated string will allow your application user to break your logging/access data which was not supposed for user access.

Base64 encoding and decoding performance: an overview of several well-known Base64 Java implementations from the performance perspective: sun.misc.BASE64Encoder,sun.misc.BASE64Decoderjava.util.Base64 (Java 8 specific), javax.xml.bind.DatatypeConverter (Java 6+), org.apache.commons.codec.binary.Base64,com.google.common.io.BaseEncoding (Google Guava), http://iharder.net/base64MiGBase64:

Tags: low latencyhigh throughputCPU optimizationserialization in JavaJava 8.

  • If you looking for a fast and reliable Base64 codec - do not look outside JDK. There is a new codec in Java 8: java.util.Base64 and there is also one hidden from many eyes (from Java 6): javax.xml.bind.DatatypeConverter. Both are fast, reliable and do not suffer from integer overflows.
  • 2 out of 4 3rd party codecs described here are very fast: MiGBase64 and IHarder. Unfortunately, if you will need to process hundreds of megabytes at a time, only Google Guava will allow you to decode 2G of data at a time (360MB in case of MiGBase64 / 720M in case of IHarder and Apache Commons). Unfortunately, Guava does not support byte[] -> byte[] encoding.
  • Do not try to call String.getBytes(Charset) on huge strings if your charset is a multibyte one - you may get the whole gamma of integer overflow related exceptions.

A possible memory leak in the manual MultiMap implementation: an overview of multimap implementations in Java 8, Google Guava and Scala 2.10 as well as a description of a possible memory leak you can have while manually implementing a multimap using Java 6 or 7.

Tags: Java collectionsJava 8ScalaGoogle Guava.

  • As you have seen, it is quite easy to miss a memory leak while implementing a multilevel map. You need to be careful and split read and write accesses to the outer map.
  • Newer frameworks and languages, like Google Guava, Java 8 and Scala already provide you more convenient syntax and wider choice of collections thus allowing you to avoid possible memory leaks in the multilevel maps.

java.util.Random and java.util.concurrent.ThreadLocalRandom in multithreaded environments: an overview of java.util.Random and java.util.concurrent.ThreadLocalRandom in single and multithreaded environments as well as some low level analysis of their performance.

Tags: Java RandomJava 7ThreadLocalRandommultithreadingCAS.

  • Do not share an instance of java.util.Random between several threads in any circumstances, wrap it in ThreadLocal instead.
  • From Java 7 prefer java.util.concurrent.ThreadLocalRandom to java.util.Random in all circumstances - it is backwards compatible with existing code, but uses cheaper operations internally.

Charset encoding and decoding in Java 7/8: we will check how fast are Charset encoders/decoders in Java 7 and what are the performance improvements in Java 8.

Tags: CharsetISO-8859-1Java 8.

  • Always prefer national charsets like windows-1252 or Shift_JIS to UTF-8: they produce more compact binary representation (as a rule) and they are faster to encode/decode (there are some exceptions in Java 7, but it becoming a rule in Java 8).
  • ISO-8859-1 always works faster than US-ASCII in Java 7 and 8. Choose ISO-8859-1 if you don't have any solid reasons to use US-ASCII.
  • You can write a very fast String->byte[] conversion for US-ASCII/ISO-8859-1, but you can not beat Java decoders - they have direct access to the output String they create.

String switch performance: we will check how fast are various ways of implementing a string-based switch.

Tags: switchJava 8String.equals/equalsIgnoreCase.

  • String switch in Java 7 is implemented using a fixed size map with a number of slots close to 20. This means that you can freely use it in most of cases not worrying about its performance at all. As you have seen, string switch has identical performance compared to manually implemented maps when you have under 100 cases in the switch.
  • String.equals/equalsIgnoreCase perform great as a replacement for string switch while all your cases have different length (or at least the number of cases with the same string length is too low compared to the total number of cases) and the number of string cases is not too big. This property is achieved by comparing string length prior to comparing the actual contents in String.equals/equalsIgnoreCase.

 

posted on 2016-12-09 14:35  哥斯达黎加  阅读(223)  评论(0编辑  收藏  举报

导航