CodeCache整理

  • JIT

    • JIT C1
      • Client模式启动速度较快
      • 桌面应用,加载速度比server模式快10%,而运行速度为server模式的10分之一
    • JIT C2
      • Server模式启动较慢
      • 服务器应用
      • 启动进入稳定期长期运行之后Server模式的程序运行速度比Client要快很多
      • 这是因为Server模式启动的JVM采用的是重量级的编译器,对程序采用了更多的优化
      • 而Client模式启动的JVM采用的是轻量级的编译器
      • 所以Server启动慢,但稳定后速度比Client远远要快
  • JIT Check

    • java -version

      java version "1.6.0_21"
      Java(TM) SE Runtime Environment (build 1.6.0_21-b06)
      Java HotSpot(TM) Client VM (build 17.0-b16, mixed mode, sharing)
      - java -version
      > java version "1.6.0_06"
      Java(TM) SE Runtime Environment (build 1.6.0_06-b02)
      Java HotSpot(TM) Server VM (build 10.0-b22, mixed mode)

  • JIT switch

    • java -version(查看jvm是64 or 32 bits)

      java version "1.7.0_15"
      Java(TM) SE Runtime Environment (build 1.7.0_15-b03)
      Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)
      - 查看JAVA_HOME/jre/bin目录下是否存在client或server目录
      - 32位的JDK一般都支持server和client两种模式
      - 64位的只支持server模式,没有client目录
      - 临时切换
      - java -client
      - java -server
      - JVM启动时 - jvm.cfg
      - 在32位JDK中,jvm.cfg位置为:JAVA_HOME/jre/lib/i386/jvm.cfg
      - 在64位JDK中,jvm.cfg位置为:JAVA_HOME/jre/lib/amd64/jvm.cfg
      - JVM 64-bit
      > -server KNOWN
      -client IGNORE
      -hotspot ALIASED_TO -server
      -classic WARN
      -native ERROR
      -green ERROR
      - JVM 32-bit
      > -client KNOWN
      -server KNOWN
      -hotspot ALIASED_TO -client
      -classic WARN
      -native ERROR
      -green ERROR

  • 解释or编译

    • -Xint
      • 不经过jit直接由解释器解释执行所有字节码,执行效率不高
    • -Xcomp
      • 不加筛选的将全部代码进行编译机器码不论其执行频率是否有编译价值,在程序响应时间的限制下,编译器没法采用编译耗时较高的优化技术(因为JIT的编译是首次运行或启动的时候进行的),所以,在纯编译执行模式下的java程序执行效率跟C/C++也是具有较大差距的
    • -Xmixed 默认
    • java -version

      java version "1.7.0_15"
      Java(TM) SE Runtime Environment (build 1.7.0_15-b03)
      Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)
      - mixed mode
      1、源代码经javac编译成字节码,class文件
      2、程序字节码经过JIT环境变量进行判断,是否属于“热点代码”(多次调用的方法,或循环等)
      3、如是,走JIT编译为具体硬件处理器(如sparc、intel)机器码
      4、如否,则直接由解释器解释执行
      5、操作系统及类库调用
      6、硬件
      - jit并不一定总能提高程序的执行效率甚至适得其反,这很大一部分取决于开发人员所写的程序质量,作为优秀的工程师应该会写出对jit友好的程序

  • 分层编译

    • jdk6u25开始引入了一种分层编译的方式,分层编译方式是一种折衷方式,在系统启动之初执行频率比较高的代码将先被C1编译器编译,以便尽快进入编译执行。随着时间推进,一些执行频率高的代码会被C2编译器再次编译,从而达到更高的性能。
    • 在实际测试时会发现不同启动方式之间启动时间差距并不明显,这是因为应用启动时还需要加载类和资源文件等,这些磁盘操作比编译更耗时,所以编译方式对启动时间的影响会被弱化
    • -XX:+TieredCompilation
    • 在jdk8中,当以server模式启动时,分层编译默认开启
    • 需要注意的是,分层编译方式只能用于server模式中,如果以client模式启动,-XX:+TieredCompilation参数将会被忽略
  • codeCache

    • 编译后的代码
    • JNI
    • 默认大小
      • 64-bit server, Java 7
        • 48 MB
      • 64-bit server with Tiered Compilation, Java 7
        • 96 MB
  • codeCache用光了?

    • 在jdk1.7.0_4之前,你会在jvm的日志里看到这样的输出:
      • Java HotSpot(TM) 64-Bit Server VM warning: CodeCache is full. Compiler has been disabled.
      • Jit编译器被停止了,并且不会被重新启动。已经被编译过的代码仍然以编译方式执行,但是尚未被编译的代码就只能以解释方式执行了
  • solution

    • 针对这种情况,jvm提供了一种比较激进的codeCache回收方式:Speculative flushing
      在jdk1.7.0_4之后这种回收方式默认开启
      而之前的版本需要通过一个启动参数来开启:-XX:+UseCodeCacheFlushing
      在Speculative flushing开启的情况下
      当codeCache将要耗尽时,最早被编译的一半方法将会被放到一个old列表中等待回收
      在一定时间间隔内,如果方法没有被调用,这个方法就会被从codeCache充清除
    • 很不幸的是,在jdk1.7中,当codeCache耗尽时,Speculative flushing释放了一部分空间,
      但是从编译日志来看,jit编译并没有恢复正常,并且系统整体性能下降很多,出现大量超时
      在Oracle官网上看到这样一个bug:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8006952
      由于codeCache回收算法的问题,当codeCache满了之后会导致编译线程无法继续,并且消耗大量cpu导致系统运行变慢
      Bug里影响版本是jdk8,但是从网上其他地方的信息看,jdk7应该也存在相同的问题,并且没有被修复。
  • 启动后负载很高的问题

    • 纯编译方式和分层编译方式都可以解决或缓解启动后负载过高的问题
    • 关于启动后负载高的原因,网上很多文章都说是由于启动后随着代码的执行,jvm的jit编译器将部分热点代码编译为目标机器代码,由于编译线程占用了大量的cpu导致系统负载高。
      为了验证这个说法,在系统启动后使用jstack获取线程dump,并通过top –H –p查看当前进程中哪些线程在大量消耗cpu。
      结果发现,编译线程虽然cpu占用率比其他线程略高,但是差距并不明显。
      另外还发现,resin处理请求的线程每一个cpu占用率虽然都不是很高,但是加起来的总占用率就相当可观了。
      因此猜测,由于jit编译器需要代码执行超过一定频率才会将其编译,系统刚启动的时候大部分代码都是出于解释执行阶段,
      而解释执行的性能会比编译执行慢很多,也因此会导致这个阶段负载很高。
      等主要的热点代码都进入了编译执行阶段,系统负载自然就恢复了
    • Jvm提供了一个参数-Xcomp,可以使jvm运行在纯编译模式下,所有方法在第一次被调用的时候就会被编译成机器代码。加上这个参数之后,系统启动之后负载确实不会上升了,但是随之而来的问题是启动时间变得很长,是原来的2倍还多
    • 分层编译方式是一种折衷方式,在系统启动之初执行频率比较高的代码将先被C1编译器编译,以便尽快进入编译执行。随着时间推进,一些执行频率高的代码会被C2编译器再次编译,从而达到更高的性能。
    • 在实际测试时会发现不同启动方式之间启动时间差距并不明显,这是因为应用启动时还需要加载类和资源文件等,这些磁盘操作比编译更耗时,所以编译方式对启动时间的影响会被弱化
    • java -XX:+PrintFlagsFinal -version | grep TieredCompilation
      • bool TieredCompilation = false {pd product}
    • 分层编译方式只能用于server模式中
    • 测试环境加上分层编译参数之后,效果很明显,在大多数情况下启动之后负载都不会升高,有时候即使有会升高,也比默认的恢复快很多
  • CodeCache

    • -XX:ReservedCodeCacheSize 一种推荐的设置思路是设置为当前值(或者默认值)的2倍 对于64位jvm,由于内存空间足够大,codeCache设置的过大不会对应用产生明显影响
    • -XX:+UseCodeCacheFlushing
      • 当codeCache将要耗尽时,最早被编译的一半方法将会被放到一个old列表中等待回收,在一定时间间隔内,如果方法没有被调用,这个方法就会被从codeCache充清除
      • jdk7在codeCache的回收方面做的很不好
      • jdk8对codeCache的回收有了很明显的改善
    • 在jdk8中,提供了一个启动参数XX:+PrintCodeCache在jvm停止的时候打印出codeCache的使用情况
  • 综合

    • mixed mode, -server, -XX:+TieredCompilation, CICompilerCount, ReservedCodeCacheSize, UseCodeCacheFlushing(jdk7做的不太好)
    • java -XX:+PrintFlagsFinal -version | grep CICompilerCount
      intx CICompilerCount = 2 {product}
      bool CICompilerCountPerCPU = false {product}
    • -XX:CICompilerCount参数这个值默认是2,也就是说2个c2的编译线程来进行编译,改为cpu core数的一半,重新启动了下效果明显比以前好了很多,load还是会冲高,不过下降的很快,因此说明这个参数是work的
    • 既然启动的时候访问量比较大,如果一直耗在解释执行时状况其实也不会多好,确实不如多拿几个线程来做编译,加快达到高峰性能的速度,而到达了高峰后,多这几个编译线程对整体并不会有什么影响

http://blog.csdn.net/lihuifeng/article/details/51672976
http://hellojava.info/?p=195
http://hellojava.info/?tag=usecodecacheflushing
https://docs.oracle.com/javase/8/embedded/develop-apps-platforms/codecache.htm#A1095915
http://blog.csdn.net/xlnjulp/article/details/26354567
http://docs.oracle.com/javase/6/docs/technotes/guides/vm/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 这篇文章是我之前翻阅了不少的书籍以及从网络上收集的一些资料的整理,因此不免有一些不准确的地方,同时不同JDK版本的...
    高广超阅读 15,565评论 3 83
  • 内建的JIT编译器、日渐成熟的垃圾收集器(多线程化)、不断改进的运行时环境(JVM Runtime Environ...
    每天学点编程阅读 492评论 0 3
  • java编译器,java解释器 1.java程序是一种可跨平台执行的语言,之所以可以跨平台,是因为jvm的存在,J...
    rabbit_coding阅读 6,990评论 2 18
  • 人要尽情地善良。
    80d58eb88df2阅读 196评论 0 0