关于Java启动性能的一个解决方法

之前的一篇文章里说到我们最近碰到的一个困扰,就是单机优化后支撑的qps(每秒请求量)确实变高了,但在高峰重启的时候有些时候会一直卡在解释执行模式,导致rt不理想,经@rednaxelafx 大神指点,可以加一个参数来基本解决。

@rednaxelafx 告诉我可以尝试加一个-XX:CICompilerCount参数来试试,这个值默认是2,也就是说2个c2的编译线程来进行编译,我改为了cpu core数的一半,重新启动了下效果明显比以前好了很多,load还是会冲高,不过下降的很快,因此说明这个参数是work的。

既然启动的时候访问量比较大,如果一直耗在解释执行时状况其实也不会多好,确实不如多拿几个线程来做编译,加快达到高峰性能的速度,而到达了高峰后,多这几个编译线程对整体并不会有什么影响。

因此看起来貌似在目前的情况下,Java启动的时候性能差在cpu够的情况下用这个办法还是能得到比较明显的缓解的,挺好的。

————————————————

之前的文章里应该是有讲过有些系统比较多的cpu消耗在了JVM_internString上,这个只有java.lang.String.intern才会调用到,可是我之前用btrace一直都没跟到谁调了这个地方,看来native method确实是不太好跟到,今天请JVM Team的人帮忙改了下JVM,允许动态打开一个参数来从JVM层面输出调JVM_internString的堆栈信息,有了这个后很快就看到了具体调用String.intern的地方,目前看起来是做序列化/反序列化的地方会调的比较多,这个对于有远程交互的应用来说会比较正常,例如java.io.ObjectStreamField的构造器代码:
public ObjectStreamField(String name, Class type, boolean unshared) {
if (name == null) {
throw new NullPointerException();
}
this.name = name;
this.type = type;
this.unshared = unshared;
signature = ObjectStreamClass.getClassSignature(type).intern();
field = null;
}

JVM会将String.intern的值放在StringTable(一个类似HashTable的结构)里,默认大小是1009,在6u34前或7前的版本,是不允许设置的,这就会导致如果很多值的话,会导致冲突严重,而使得链表很长,那么在调用String.intern的时候由于遍历链表,会导致耗CPU会比较多。

————————————————

最近有个应用还碰到比较明显的CMS GC时ygc时间有点偏慢的现象,后来dump内存分析的时候看到有个较大的数据结构是一直存活的,问了下开发,这个数据结构里的对象是会经常变的,对于这种情况,CMS GC的ygc速度是会受到一些影响的(话说不仅仅是cms gc,所有GC都会),原因是ygc的时候需要扫描卡表,这个卡表主要是标识新生代中哪些对象是被旧生代引用了的,这种需要尽可能避免,但确实不好做到。

=============================
题图来源于:http://cn.wsj.com/pictures/photo/Another_Lamborghini_Supercar/06.jpg
欢迎关注微信公众号:hellojavacases

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

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

发表评论

电子邮件地址不会被公开。 必填项已用*标注


*