关于Java启动时的速度

很多流量大的Java应用在重启的瞬间很容易出现负载比较高的现象,通常会看到的原因可能是GC线程、业务处理线程以及JVM编译线程耗CPU较多,这个问题在目前要解决其实是比较困难的,原因如下。

Java程序在启动的时候所有代码的执行都处于解释执行模式,只有在运行了一段时间后,根据代码方法执行的次数,或代码里循环的执行次数等达到一定的阈值才会编译成机器码,编译成机器码后执行效率会得到大幅提升,而随着执行时间进一步拉长,JVM的各种更高级的编译优化手段就会逐渐加上,例如if条件的执行状况,逃逸分析等,具体的更多信息可以看看以前撒迦写的Java执行的PPT。

因此Java程序要达到一个比较稳定的高效的代码执行是需要一定的时间的,为了解决这种问题,通常来说暂时可以采用的解决方法是:
1. 主动对Java程序进行热身
在启动完成后,主动的访问热点的代码入口,确保主要的热点代码编译成机器码后再放入流量,可通过-XX:+PrintCompilation来确认。

2. 逐步放进流量
通过apache/nginx转发等逐步的放入流量,用流量来完成Java程序的热身也是一种方法,但通常来说这个操作起来比较复杂。

对于特别重要的应用,建议用第一种方法,不过通常操作起来也比较折腾。

在写一些micro benchmark代码前也请一定要记得先做warm动作,避免测试结果偏差太大。

另外,Oracle JDK从JDK 6u25以后的版本支持了多层编译(-XX:+TieredCompilation),默认是不打开的(可以用jinfo -flag或-XX:+PrintFlagsFinal来确认是否打开),这个的好处是之前server都是采用c2高级编译的,会比较耗时且要运行一段时间才会触发编译,而c1编译是比较轻量的也比较快触发,因此在启用了多层编译后,可以在启动后更快的让部分代码先进入编译模式,感兴趣的同学可以自行找下关于多层编译的一些资料。

之前听到一个消息是,Oracle JDK为了解决某个问题做的一个改进,有可能能用于提升Java应用的启动速度,也算是无心摘柳柳成荫,:),不过暂时貌似还没有什么新的进展的消息。

另外,再啰嗦说下,传说中的大方法的执行效率更低,是有可能的…原因是inline优化,Oracle JDK会有默认的MaxInlineSize的控制,如果大于了这个值,在做Inline优化的时候就会跳过,从而导致在执行方法时要多几个指令,因此方法的大小还是要稍微控制下的。

关于Java程序执行的一些原理知识,推荐看下@rednaxelafx之前写的一个巨长的PPT,:)

昨天的调查结果让我还比较欣慰,结果显示订阅我这个账号的大部分是非阿里的,挺好,:),不过话说这是我这个公众账号一天收到的最多消息的一次,希望大家有什么问题,或希望看到分享的,或希望给其他人分享的都回复我,如果有希望给其他人分享的最好了,现在微信5.0已经支持在公众账号上写作者名字了。

最后推荐下阿里技术嘉年华的微信公众号:alibabatech 会有很多阿里各种技术的分享信息,阿里在技术上还是一家比较开放的公司,因此还是能得到一些信息的。

话说阿里技术嘉年华应该算是搞得很不错,干货很多的技术大会,尽管今年开始收费了(MM不收费,这个一定要继续保持下去,:)),但价格很便宜,所以能来参加的话我觉得还是值得参加下的(尽管我个人现在对各类技术大会都不感兴趣了…)。

=============================
题图来源于:http://img0.pcauto.com.cn/pcauto/1108/31/1624710_21.jpg
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

微信互动问答

最近微信上的几个问题,我觉得还是有必要单独发一条信息来回答,:),也欢迎大家继续发送问题,分享你排查的case(如果有投稿,那是极度的欢迎),还有Java使用中碰到的一些“坑”。

问:btrace能否介绍一下调试经验?
答:btrace绝对是我排查问题工具集中的神器(内核级别systemtap也是神器,但它对性能的影响显然要比btrace大多了),btrace是生产环境运行时可使用的(也有些小问题,例如退出的时候可能有些残留等),btrace的使用非常简单,从官网上把btrace的tgz包下载解压后,通常修改下bin/btrace,主要是增加JAVA_HOME,将btrace改为可执行,接着就可以编写Java作为脚本来执行了,具体btrace使用的一些简单脚本的例子可见此篇文章,另外我可以给的建议是btrace这东西想用的熟练的话,就在自己本机的java代码里多试试就OK了,例如随便写段程序,跟踪下里面java.util.HashMap.put的调用堆栈,跟踪下调用时间消耗、传入的参数和返回值等,话说前几天我在生产环境用btrace还碰到个问题,我跟踪的那个方法输出的信息太多,结果为了让btrace停止,我按了多次ctrl+c,然后回车,估计按太多次了,竟然导致目标进程的heap被用满了,一直fgc。

问:最近有人说,在java里。尽量不要用大的try catch. 因为那样try块中的代码执行效率会降低,我也是第一次听说,之前我们都会在业务层把所有的代码的异常都捕获掉。这个问题还没找到答案。你怎么看的。
答:话说这个说法我还真不知道理由是什么,按照我知道的Java执行原理来说,不要在一个方法体里写过多行数的代码倒是有道理的,因为确实会导致性能下降,这种情况下性能下降的原因有两个:一是因为Java对运行时从bytecode–>native code的编译的方法默认有大小的限制,默认限制的大小为8000bytes,当一个方法超过8000bytes时,将不会对其进行编译,可通过-XX:-DontCompileHugeMethods来强制允许编译,但那样会导致codecache的区域被用满的可能性大增(上一个RT下降的Case就是因为code cache被用满);二是因为Java对inline方法的大小也有大小的限制,inline方法的大小限制通常很小,例如默认值是35bytes(可用jinfo -flag MaxInlineSize [pid]来查看),inline后方法的执行会加快一些(毕竟少了跳的步骤)。

问:你好,请问有办法查看java线程的网络流量么。我有一个程序要访问很多网络服务,运行一段时间后带宽就被占满了,并且一直维持这个状态。请问怎么排查这种情况。谢谢。
答:这种我还真不知道,我能想到的办法就是tcpdump看看主要是哪些频繁的请求,或者就是根据使用的网络框架等用btrace跟踪收发包部分的代码(例如可跟踪序列化/反序列化部分的代码),看看是什么地方在频繁做动作或收发较大的包。

问:jdbc和hibernate的选择
答:我的回答是对性能要求很高的场景,还是直接用jdbc吧,hibernate固然好用,但有个主要的问题是生成的sql看起来很痛苦,另外是还得等运行时生成,对于很多对性能敏感的应用而言,最好是所有用到的sql都能提前评估。

问:也碰见’占用系统内存不释放’查到os:malloc占用大多数”’没有思路了
答:这个问题的背景就是堆外内存被耗光,显然这已经用google perf-tools跟踪过了,看到了os::malloc占用了最多,这个时候可以进一步用pprof –gv来图形化的跟踪下os::malloc的堆栈,如果看到是unsafe_allocate,又如果是server端程序,那基本上可以肯定是由于Direct ByteBuffer造成的(因为Java中通常只有Direct ByteBuffer和AWT会调用unsafe来做allocate,实在不行还可以用btrace跟跟),这种情况下通过增加-XX:MaxDirectMemorySize可解决(具体也可参见这篇文章中的几个Case)。

问:请教您一个经验问题,就是缓存系统一般设置访问超时时间是多少?我们一个后台核心系统最近上了缓存memcached,用于实时计数,但是由于环境以及压测不够的原因,系统上线后跑了一段时间后突然出现大量缓存访问超时,而我们的超时时间是设置了两秒,导致整个系统都处理缓慢了。。我想要的是即使缓存在出问题的时候也不要拖慢系统。所以想问下您这里缓存系统的访问超时时间一般是多少比较合理?
答:对于大访问量系统而言,超时时间绝对是个超级敏感的值,当年我上线一个系统的时候就是由于其中一个远程调用的默认超时时间是1分钟而导致了一次严重故障,缓存这种无论如何都应该是非常快速完成的一个动作,因此通常建议其超时时间设置为50ms或100ms,即使是复杂逻辑的远程调用,我们通常也会把超时时间控制在1s以下,避免依赖的服务端变慢而导致自己的请求线程被耗光。

ps: 最近的一个排查了将近一周多时间的case是和Groovy相关的case,之后再来专门写篇文章说说Groovy的使用,要在生产环境中用好Groovy(尤其是大量使用)还是要小心不少“坑”的,但Groovy确实有一些好处,所以有些事。

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。