64位JVM带来的问题及解决方案

标签: jvm 问题 | 发表时间:2014-05-05 17:18 | 作者:
出处:http://it.deepinmind.com

这篇文章会检验你有关JVM的知识以及项目交付相关的技能;尤其是涉及到JVM升级的时候。期待你们的评论及回复,一起探讨下如何规避这类的项目可能产生的性能问题。

背景

最近碰到了一个影响到线上生产环境的问题,我们使用的是WebLogic 10以及32位的Hotspot JVM 1.6 。鉴于目前的一些问题以及未来负载上升的预测,我们决定将HotSpot JVM 1.6升级成64位的。

注意我们并没有修改JVM的启动参数。

经过几周的功能测试及规划,这次升级成功地部署到了线上环境。不过,技术支持团队发现第二天便出现了严重的性能下降,其中还有线程锁竞争的问题,迫使部署团队不得不回滚了这次升级。

最终我们找到了问题的原因,而这次升级也将在最近重新进行发布。

问题:

从上面这些信息来看,说一下你认为可能导致这次性能下降的原因。

说一下这次升级有什么好处,对于这类升级的如何进行管理以及降低风险,给出一些你的建议。

答案:

我经常听到有人说只要从32位JVM升级到64位就能自动获得性能的提升。这只说对了部分。有显著的性能提升的前提是在这之前你的系统存在内存占用的问题比如过度GC或者java.lang.outofmemoryerror,并且你也进行了适当的调优及堆大小的调整。

不幸的是,我们通常都忽略了一个事实,对于 64位的JVM来说,系统中的本地指针会占用8个字节,而不是4个。这会导致你的程序的内存占用量的增加,因此会带来更频繁的GC以及性能的下降。

下面是Oracle的官方解释:

64位的虚拟机和32位的比起来,性能上有什么不同?

一般来说,和32位的虚拟机相比,同样的程序在64位机上仅需花费很小的 性能损失就能获得更大的寻址空间。这是由于系统的本地指针在64位虚拟机中会占用8个字节。这些额外字节的加载会对内存的使用带来影响,其结果就是程序执行的速度会变稍微的变慢,具体是多少取决于你的Java程序在执行的过程中需要加载多少指针。好消息是AMD64和EM64T平台在64位模式下运行的时候,Java虚拟机能获得额外的寄存器,来生成更高效的本地指令序列。这些额外寄存器带来的性能提升几乎能弥补64位虚拟机带来的执行速度的下降。SPARC平台上64位虚拟机和32位的相比,大概会有10%~20%的性能下降。AMD64和EM64T平台上则大概是0%~15%,这取决于你应用程序执行的时候有多少指针了。

现在回到我们开始说的那个问题上,内存占用量有了显著的增加,这就是导致性能问题的罪魁祸首。根据你选择的GC策略,GC的老生代回收会导致JVM和线程的暂停时间变得更长,这引发了线程锁竞争以及其它的问题。从下图可以看到,升级到64位JVM后应用程序的内存占用量(老生代)增加了45%。

Java堆的使用量 ~老年代回收后占用量大概是900MB(32位)

Java堆的使用量 ~老年代回收后占用量大概是1.3GB(64位)

应用程序的Java堆的内存占用量增加了45%。当然这是本地指针的大小膨胀了的缘故。

还有一个问题就是在项目支付前,只进行了功能测试,而没有进行性能测试及压力测试。并且也没有对JVM参数的进行修改或者调整,这自然就增长了旧生代回收的频率以及GC的暂停时间。最终的解决方案是将堆的大小从2GB增加到2.5GB,并且开启压缩指针的选项。

现在你已经明白问题是什么了,下面是我关于类似升级的一些建议:

  1. 进行性能压测,比较下应用程序在32位和64位时的内存占用量和GC的表现。
  2. 确保有足够的时间来进行GC参数及堆大小的调优,以便减少GC的暂停时间。
  3. 如果你用的是HotSpot JVM1.6 6u23以后的版本,可以启用指针压缩这个选项。这个选项使得JVM可以通过Java堆的某个64位的起始地址的32位的偏移量来表示大部分的指针;这样就减少了升级再来的内存占用量的增加。
  4. 正确地规划你的JVM进程所在的宿主机的容量。确保内存和CPU的能力满足这次升级带来的额外的内存和CPU的消耗。
  5. 采用一种低风险的升级策略,只升级线上环境的部分机器到64位JVM,比如说25%~50%。这样你还可以比较下现有的32位机器以及新升级的机器的表现,确保性能带来的收益及损失满足你的预期。

原创文章转载请注明出处: 64位JVM带来的问题及解决方案

英文原文链接

相关 [jvm 问题] 推荐:

JVM问题定位工具

- - 四火的唠叨
文章系本人原创,转载请保持完整性并注明出自 《四火的唠叨》. JDB是基于文本和命令行的调试工具,Jikes在JDB的基础上提供了GUI. 熟悉JDB还是有价值的,很多情况下需要我们在命令行下完成简单的debug问题定位. 我们可能更熟悉使用下面这样的方式来进行调试,但本质上就是在使用JDB:.

JVM CPU 使用率高 问题两则

- - 码蜂笔记
最近有两个系统先后被恶意扫描,出现 CPU 使用率高的现象. CPU 使用率很高,首先是要找出 CPU 在执行什么样的代码,然后在分析这些代码有什么问题. 1、 用命令 “ps aux | grep APP” 找出应用的进程 id:. 2、 找出耗CPU的线程,在Linux系统下用命令: “ top –H –p pid ”, pid 就是前面找出来的应用进程 ID.

java.util.zip.Deflater使用不当引发jvm crash及问题排查

- - Linux - 操作系统 - ITeye博客
最近使用第三方开源库jflvlib录制flv格式视频,测试过程发现,视频录制进程经常挂掉;. java启动参数中已经配置内存溢出时导出日志文件-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/Logs/xxx.dump和jvm crash的日志输出路径-XX:ErrorFile=/export/Logs/xxx.log,但是进程挂掉后没有找到任何日志输出;.

64位JVM带来的问题及解决方案

- - Java译站
这篇文章会检验你有关JVM的知识以及项目交付相关的技能;尤其是涉及到JVM升级的时候. 期待你们的评论及回复,一起探讨下如何规避这类的项目可能产生的性能问题. 最近碰到了一个影响到线上生产环境的问题,我们使用的是WebLogic 10以及32位的Hotspot JVM 1.6. 鉴于目前的一些问题以及未来负载上升的预测,我们决定将HotSpot JVM 1.6升级成64位的.

JVM 调优 —— GC 长时间停顿问题及解决方法

- - ImportNew
垃圾收集器长时间停顿,表现在 Web 页面上可能是页面响应码 500 之类的服务器错误问题,如果是个支付过程可能会导致支付失败,将造成公司的直接经济损失,程序员要尽量避免或者说减少此类情况发生. 并发模式失败(concurrent mode failure). 在 CMS 启动过程中,新生代提升速度过快,老年代收集速度赶不上新生代提升速度.

关于JVM(JDK),Tomcat,Linux的最大线程数问题

- - 孟飞阳的博客
一、JVM(JDK)最大线程数. JVM最大创建线程数量由JVM堆内存大小、线程的Stack内存大小、系统最大可创建线程数(Java线程的实现是基于底层系统的线程机制来实现的,Windows下_beginthreadex,Linux下pthread_create)三个方面影响. -Xmx  最大堆内存.

jvm 在docker中内存占用问题探索 | Truman's Blog

- -
jvm 在docker中内存占用问题探索. 最近有个项目在PRD上部署,因为涉及到读取大量数据,会出现内存占用. 为了避免因为该项目影响线上其他服务,所以设置了-m=2048,结果发现运行会超过这个值,docker 进程即将该container killed.. 随后设置了好几个级别,直到-m=6048,依然无法避免container 被干掉.

一次大量 JVM Native 内存泄露的排查分析(64M 问题)

- - 掘金后端本月最热
我们有一个线上的项目,刚启动完就占用了使用 top 命令查看 RES 占用了超过 1.5G,这明显不合理,于是进行了一些分析找到了根本的原因,下面是完整的分析过程,希望对你有所帮助. Linux 经典的 64M 内存问题. 堆内存分析、Native 内存分析的基本套路. tcmalloc、jemalloc 在 native 内存分析中的使用.

JVM研究

- - 开源软件 - ITeye博客
每天接客户的电话都是战战兢兢的,生怕再出什么幺蛾子了. 我想Java做的久一点的都有这样的经历,那这些问题的最终根结是在哪呢. JVM全称是Java Virtual Machine,Java虚拟机,也就是在计算机上再虚拟一个计算机,这和我们使用 VMWare不一样,那个虚拟的东西你是可以看到的,这个JVM你是看不到的,它存在内存中.

jvm调优

- - 互联网 - ITeye博客
printf "%x\n" 21742  找到耗时最长的进程. jstack pid | grep 54ee  定位某个类的方法. jstack 10535|grep -A 10 2a1d (最后十行). jmap 查询pid 内存线程. 附:TOP命令中需要关注的值:. (1)load average:此值反映了任务队列的平均长度;如果此值超过了CPU数量,则表示当前CPU数量不足以处理任务,负载过高.