在没遇到这个问题之前,我对JVM的解释模式与编译模式的代码性能相差有多大,是没有感觉的,只是觉得编译模式会比解释模式性能好那么一点点吧。

但是经历过这次以后,让我对JVM的即时编译产生了兴趣。先来看看这个问题的背景:

  大概是4年前,我的团队里有一个PM找我说他们遇到一个很奇怪的问题,在性能测试的时候,有几个不同的测试场景混合在一起进行压力测试,有时会出现测试几十几分钟以后性能会下降的很厉害,一旦出现性能下降以后,性能再也回不到刚开始测试的水平。奇怪的是:它不是必现的,而且如果只是某1个或者2个场景一起测试的话,不会出现。

  因为不是网上问题,所以我有时间坐下来好好分析,先安排老思路排查,按我遇到的经验一般性能瓶颈是某些资源遇到了瓶颈,这些瓶颈可以是磁盘IO、网络IO、CPU、内存等,然后使用相应的Linux命令一一排查。在排查到CPU的时候,发现CPU比较高,然后使用jstack多次取堆栈进行分析,但是发现每次堆栈的栈顶都不太一样,但是从栈顶再往下看,能看到都是停留在我们使用的一个商用软件Volantis MCS的堆栈上。Volantis MCS即Volantis Multi Channel Server,它的作用是使用某种开发语言开发一个页面,在用户通过手机访问时会根据用户的手机的User-Agent自动转换成最适合手机展示的xhtml页面,就是我们常说的终端适配了。

  它与我们以往的不一样的是以前出现的CPU高一般堆栈都是集中在某一个或者几个方法上,而这次是分散在很多处,有点犯难了。

  由于是商用软件,没有源代码,我只能把取到一些典型的堆栈记下来,然后反编译代码,看到经常在jstack上处于Runnable的栈顶的代码并不是很复杂的逻辑,只有一些基本的字符串、+-*/这样的运算。因为性能压测tps比较高,直接使用JProfiler工具的话,性能是压不上去的,只能拿出我的杀手锏了: 把class反编译以后,自己加了一些统计性能的代码,并定期的打印出来。虽然方法有点土,但是直接有效。

  打印出统计日志以后,就发现问题所在了,同样没有任何IO操作的方法,在出现问题前调用一次在3~5ms,而出现问题以后这个方法平均时长为20~30ms。难道是输入不一样吗?随后又增加日志把输入也打印出来,发现完全一样。

  同样的输入,同样的代码,竟然性能相差这么大,难道是机器上有其它进程(线程性能影响),排查了也没有呀。

  这时突然灵光一现,是不是因为这段代码在一定情况下没有编译成本地代码,而是在解释模式下运行的?是不是编译代码时也有缓存大小,在网上查了一下我所用的JDK版本的默认的代码缓存是64M,在官方找到了对应版本的配置,并根据网上的信息如果发生这种问题,会在gc日志会打印一句warning,具体的warning是什么忘记了。反正我们的机器的内存配置一般至少都是32G,代码缓存配置为128M也不为过,配置了以后不论怎么测试都OK了.

   回过头了想想为什么会有时出现有时没有?猜测原因大概是这样的,因为我们应用代码量非常大,使用了很多第三方软件,特别是Volantis MCS这样非常耗CPU的组件执行的频率如此之频繁,在某一种场景下,如果先测试某个流程会导致那个流程中大量的代码被转换成本地代码,然后再执行这些非常频繁的代码的时候代码的缓存因为耗尽了,就只能采用解释的方式执行。

  事情到这里其它我最感兴趣的地方才刚开始:

  1、解释模式与编译模式性能究竟相差多少?

  2、为什么编译以后的代码性能这么高?

  第一个问题我做了测试,把JVM的配置修改为纯解释模式,原来几分钟启动的应用,等了有20分钟左右还没有完全启动起来,要知道我们用的服务器一般至少都是4核心的。第二个问题,下载了openjdk的代码,看了x86的c++的代码,发现太复杂了,当时放弃继续研究。直到去年的时候,我离开华为的时候有了一些自己的时间,自己买了一本《Hotspot实战》并在iteye上有一个高级虚拟机的组的一些前阿里大神的一些文章,结合openjdk 8的代码,才慢慢对编译的原理有些感觉。为什么性能相差这么大,我的理解解释模式采用套用代码调用的模板,每一个指令选择一个template,把执行的template的汇编代码打印出来,可以看出来一个很简单的指令都会生成一堆指令。而编译模式有C1和C2 2层优化(http://hllvm.group.iteye.com/group/topic/39493),JVM先把汇编指令转换成一种中间的代码格式ad,再采用传统的编译器的优化优化技术,这些优化技术是集国外的各大神的技术精髓,所以它重新生成的代码比你手工写的代码质量高就一点不奇怪了。

  随着逐步深入,发现原来JVM的GC又是一块宝藏。话题有点扯远了,发现自己懂的太少了,JVM里面好玩的东西太多了,学习中...

jvm的代码缓存耗尽导致性能下降的更多相关文章

  1. MySQL字符集不一致导致性能下降25%,你敢信?

    故事是这样的: 我在对MySQL进行性能测试时,发现CPU使用率接近100%,其中80%us, 16%sys,3%wa,iostat发现磁盘iops2000以下,avgqu-sz不超过3,%util最 ...

  2. Optional 的使用会导致性能下降吗?

    几天前,我在论坛上发了一篇关于Optional 的文章.其中一条评论是一个非常好的问题: Optional 的使用会导致性能下降吗? 答案是: 是的,它会的.但是你应该担心吗? 使用Optional的 ...

  3. SQL Server ->> 性能调优案例之 -- 包含递归查询的视图导致整个查询语句性能下降

    有个语句最近性能下降很厉害,原本1秒就可以查询完毕的事情现在居然需要3-4分钟. 首先我的做法是先快速找出导致整个语句下降的元凶.在这个例子里面查询语句有3个JOIN字句,我通过删除某一个JOIN节点 ...

  4. Oracle迁移到MySQL性能下降的注意点(转)

    背景:最近有较多的客户系统由原来由Oracle改造到MySQL后出现了性能问题CPU 100%,或是后台的CRM系统复杂SQL在业务高峰的时候出现堆积导致业务故障.在我的记忆里面淘宝最初从Oracle ...

  5. JVM 性能调优实战之:使用阿里开源工具 TProfiler 在海量业务代码中精确定位性能代码

    本文是<JVM 性能调优实战之:一次系统性能瓶颈的寻找过程> 的后续篇,该篇介绍了如何使用 JDK 自身提供的工具进行 JVM 调优将 TPS 由 2.5 提升到 20 (提升了 7 倍) ...

  6. 使用阿里开源工具 TProfiler 在海量业务代码中精确定位性能代码 (jvm性能调优)

    技术交流群:233513714 本文是<JVM 性能调优实战之:一次系统性能瓶颈的寻找过程> 的后续篇,该篇介绍了如何使用 JDK 自身提供的工具进行 JVM 调优将 TPS 由 2.5 ...

  7. [转帖]Java虚拟机(JVM)体系结构概述及各种性能参数优化总结

    Java虚拟机(JVM)体系结构概述及各种性能参数优化总结 2014年09月11日 23:05:27 zhongwen7710 阅读数 1437 标签: JVM调优jvm 更多 个人分类: Java知 ...

  8. Databricks缓存提升Spark性能--为什么NVMe固态硬盘能够提升10倍缓存性能(原创)

    我们兴奋的宣布Databricks缓存的通用可用性,作为统一分析平台一部分的 Databricks 运行时特性,它可以将Spark工作负载的扫描速度提升10倍,并且这种改变无需任何代码修改. 1.在本 ...

  9. MySQL 5.7 分区表性能下降的案例分析

    转载自:https://mp.weixin.qq.com/s/K3RpSBAIWFwGCIWyfF0QPA 前言:希望通过本文,使MySQL5.7.18的使用者知晓分区表使用中存在的陷阱,避免在该版本 ...

随机推荐

  1. SQL位运算符

    十进制 170 转二进制为:0000 0000 1010 1010 十进制 75  转二进制为:0000 0000 0100 1011 1.&(位与) 上下运算,按照与的运算规则:0& ...

  2. Adaboost 算法

    一 Boosting 算法的起源 boost 算法系列的起源来自于PAC Learnability(PAC 可学习性).这套理论主要研究的是什么时候一个问题是可被学习的,当然也会探讨针对可学习的问题的 ...

  3. simple_html_dom配合snoopy使用

    https://github.com/samacs/simple_html_dom Snoopy的特点是“大”和“全”,一个fetch什么都采到了,可以作为采集的第一步.接下来就需要用simple_h ...

  4. 推荐一个自动抽取pdf高亮笔记的web应用

    很多人可能像我一样,喜欢用电脑或平板阅读pdf格式的论文或电子书,阅读过程中难免会使用highlight(高亮)工具标记出重要的文字和段落.有没有办法将所有高亮的部分抽取出来,形成一篇单独的笔记呢?下 ...

  5. Javascript 事件对象(三)事件冒泡

    事件流---事件冒泡取消冒泡:ev.cancelBubble=true ---事件捕获Ie下是没有的,在绑定事件中,标准下是有的 <!DOCTYPE HTML> <html> ...

  6. [转]透过 Linux 内核看无锁编程

    非阻塞型同步 (Non-blocking Synchronization) 简介 如何正确有效的保护共享数据是编写并行程序必须面临的一个难题,通常的手段就是同步.同步可分为阻塞型同步(Blocking ...

  7. (转)iOS安全 对本地文件的保护

    开篇先扯几句题外话,许多朋友都问我怎么不写防啊,我确实有点犹豫.hackers总是想象如果自己是开发者会怎么写,然后才能找到入手点.同理,开发者们也要想象自己是hackers会怎么做,才能采取相应的防 ...

  8. 嵌入式(Embedded)Neo4j数据库访问方法

    应用中采用嵌入式Neo4j(Embedded Neo4j)数据库,插入数据后不知道如何访问.查询之后知道有Neoclipse这个可视化工具,最新版本是1.9.5.添加目录后报错: 应该是Neoclip ...

  9. keras 入门之 regression

    本实验分三步: 1. 建立数据集 2. 建立网络并训练 3. 可视化 import numpy as np from keras.models import Sequential from keras ...

  10. ulua 路径小记 以及 lua require 机制整理

    ulua 路径小记 在学习ulua时,require模块的根路径可以为项目的Lua文件夹或者ToLua文件夹(Editor下),但是在package.path和package.cpath中并没有看到当 ...