Jvm内存管理基础

1,942 views

Published on

Published in: Technology, News & Politics
0 Comments
12 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,942
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
128
Comments
0
Likes
12
Embeds 0
No embeds

No notes for slide
  • 可能 jdk7 也改进了相似字符串的压缩?
  • Jvm内存管理基础

    1. 1. JVM 内存管理基础 hongjiang 2012.7
    2. 2. 说明► 课程目的 帮助 Java 程序员更好的认识 JVM ,掌握 GC 基础知识,了解现有线上业务的 GC 配置及问 题► 大纲 1: JVM 内存结构 从对象的创建和消亡过程看内存 2: GC 的选择 了解各种 GC 的特点,选择的依据 3: CMS GC 详情 详细了解 CMS GC 的特点 4: 当前业务线线上的 GC 配置 参考集团各子公司业务线的 GC 配置以及问题► 学习对象要求 Java 程序员 <= P6► 联系我: http://laiwang.com/u/3001
    3. 3. 第一部分从对象的创建与消亡过程看 JVM 内存
    4. 4. JVM 运行时数据区 heap non-heap Native VM Hotspot 里 Method Stack 本地方法栈 Stack堆空间,不同的 与 java 栈在GC 策略有不同的 Program counter 一起 划分方式 register Method Area
    5. 5. 类的初始化► 引子,初始化问题public class TestA{ static { a = 1; } static int a = 0; // 1) 如果不赋值呢? 2) 如果这一句与上一句位置互换? public static void main(String[] args){ System.out.println(TestA.a); }}
    6. 6. 例子 2► 模板模式使用不当遇到的问题
    7. 7. 类的初始化:生命周期Load Link Initialize加载 连接 初始化 ? <clinit> classload
    8. 8. 类的初始化:生命周期 展开其中的 Link 过程,又有三个步骤: 看另一段初始化的代码 Verify Prepare Resolve (校验) (准备) (解析) 为类变量分配内存,设置 默认值。注意:此时在 <clinit> 之前http://frankkieviet.blogspot.com/2009/03/javalanglinkageerror-loader-constraint.html//FIXME
    9. 9. 类的初始化: <clinit> 的问题► 此过程的数据主要在哪个区域?► 看一段代码例子: 中文站曾大面积发生过的现象 ( 高并发情况 下) 基础框架里 (toolkit.common.lang) 里潜伏 的简化后的代码:
    10. 10. class Lock {}class Danger { static { System.out.println("clinit begin..."); try {Thread.sleep(2000);} catch (Exception e) {} synchronized (Lock.class) { System.out.println("clinit done!");} }}public class Test { public static void main(String[] args) { new Thread() { public void run() { synchronized (Lock.class) { System.out.println("new thread start!"); try {Thread.sleep(1000);} catch (Exception e) {} new Danger(); } System.out.println("new thread end!"); } }.start(); try {Thread.sleep(500);} catch (Exception e) {} System.out.println(new Danger()); System.out.println("DONE!"); }}
    11. 11. 诊断方法► jstack javapid > file► printf “%0x” threadId对工具的使用另外展开一个话题,参考:http://www.slideshare.net/hongjiang/effective-linux2toolshttp://www.slideshare.net/hongjiang/effective-linux3diagnosis
    12. 12. 类的初始化: 运行时数据区与线程安全 heap non-heap VM 线程私有 Stack 除了在 Eden 区 每个线程分配一块缓冲 (TLAB) ,在该区 Program counter register 线程私有 是线程私有。其他都是线程共享的 Perm gen 线程共享
    13. 13. 类的初始化: 运行时数据区与线程安全► <clinit> 更新类的数据是在 perm gen 区域► 当多个线程需要初始化一个类,仅仅运行一 个线程来进行,其他线程需要等待 (object.wait) 。当活动的线程完成初始化之 后,它必须通知其他等待线程。
    14. 14. 类的初始化: PermGen 的数据内容Class mate data 基本类型信息 动态连接类型信息 依赖的数 类型常量池 据 字段信息 字节码 方法信息 类成员 ( 静态变量 ) 通过 classloader 引用 <clinit> 来修改 Class 类实例的引用
    15. 15. 类的初始化► 常量池的内容 // TODO► 怎么查看常量池中的字符串常量 // 参考 PermStat.java 的实现 class StringPrinter implements StringTable.StringVisitor
    16. 16. 类的初始化: <clinit> ,与内存无关的题外话下面的代码是否会有 <clinit> 方法?public class A{ public static final String FLAG = “hi”;}引申,另一个中文站发生过的案例$ javap –verbose
    17. 17. 类的初始化: PermGen 区域的变数► 未来 Jdk7 的某个 update 可能将 PermGen 彻底去除, class metadata 将放入 C-heap 区域。 Hotspot 与 JRockit 整合。► java7目前 release 的版本中,已经将字符串 常量池移到了 main heap ( 对于分代 gc 来说 是 old gen 区域 )看一个例子:
    18. 18. 类的初始化: PermGen 区域的变数1 ) 调用 String.intern()scala> for(i <- 0 to 3000000)new String("xxxxxxxxxxxxxxxxx" + i).intern对比 jdk6 与 jdk7 的差异2 )产生随机的大字符串做常量,对比 jdk6/7看看存在哪儿?
    19. 19. 对象的创建► 当你创建一个对象实例时,被放到了哪儿? Stack ? 有可能么? Heap ? Eden ? Old Gen ?
    20. 20. 对象的创建► 了解一个前提:基于逃逸分析 (Escape Analysis) 的优化: $ jinfo –flag DoEscapeAnalysis javapid 在 server mode(c2) 下是默认开启的 (jdk6 u23 之后 ) 1) Stack Allocations 栈上分配 在 jdk7 上还没有实现 也许在 jdk8 上对 closure 可以实现在栈上分配 ( 别相信我 ) 2) Synchronization Elimination 同步消除 -XX:+EliminateLocks 默认已开启 3) Scalar Replacement 标量替换 -XX:+EliminateAllocations 默认已开启
    21. 21. 对象的创建: Allocations1) 在 stack 上创建(未来可能)最高效 ,避免了 GC ① Stack ② TLAB2) 在 TLAB 区域创建,避免了竞争的代 Heap 价 ( 默认 ) ( Eden) ③3) 在 Eden 区域创建 ( 默认 ) ④ Heap (Old)4) 在 Old 区创建,需满足条件,比如对 象大于阈值
    22. 22. 对象的创建: Allocations► fast allocation 1) bump the pointer 前提:有大块的连续空闲空间 内部维护一个指针( allocatedTail ),它始终指向先前已分配对象的尾部,当新的对象分 配请求到来时,只需检查代中剩余空间(从 allocatedTail 到代尾 geneTail )是否足以容纳 该对象 2) thread local allocation buffers(TLABs) 避免了多线程竞争同步的开销 在 TLABs 区域也可以采用 bump-the-pointer 方式
    23. 23. 对象的创建: TLAB► Thread Local Allocation Buffer https://blogs.oracle.com/jonthecollector/entry/t https://blogs.oracle.com/jonthecollector/entry/ https://blogs.oracle.com/jonthecollector/entry/a https://blogs.oracle.com/jonthecollector/entry/
    24. 24. 对象的创建: TLAB► TLAB 的参数-XX:+UseTLAB 启用 TLAB 默认开启-XX:+ResizeTLAB 动态设置每个线程的 tlab 大小 默认开启-XX:TLABSize=X TLAB 初始大小 默认 0-XX:TLABWasteTargetPercent=X 占 Eden 区的百分比 默认 1%-XX:PrintTLAB 打印 TLAB 相关信息 默认不开启
    25. 25. 对象的创建 : Eden► 在 Eden 区分配 TLABs 未开启或无可用空间► Eden 区空间不足时 minor gc  存活对象从 Eden 移动到 Survivor Survivor 区空间不足则晋升到老生代
    26. 26. 对象的创建 : Tenured► 直接分配在 old gen 的例子:$ scala -J-Xms100m -J-Xmx100m -J-Xmn50m -J-XX:PretenureSizeThreshold=2097152 -J-XX:+UseConcMarkSweepGCscala> System.gcscala> val data = new Array[Byte](10*1024*1024)scala> System.gcscala> println(data.length)配合 jconsole 观察 old 区的内存变化注意,在 Parallel Scavenge GC 下使用 PretenureSizeThreshold 无效,Parallel Scavenge GC 的新生代采用自适应策略自动调节各区域空间
    27. 27. 指定区域大小的参数与 OOM 的可 能 heap non-heap VM -Xss Stack 唯一没有规 定 OOM 的区 Program counter -Xms 域 register -Xmx -XX:PermSize -Xmn -XX:MaxPermSize Perm gen JIT 缓存 Code Cache -XX: ReservedCodeC acheSize
    28. 28. Stack 区的几点吐槽1) -Xss 和 -XX:ThreadStackSize 是一回事,– Xss 是面向所有 JVM ,后 者是 hotspot 专用, hotspot 会把 Xss 转换为 ThreadStackSize3) 查看 java 进程的栈大小时通过 jinfo –flag ThreadStackSize javapid5) 在不同的 OS 和架构 (32/64)Xss 默认值也是不同的, 64 位 linux 上默 认是 1024k (1m) ,在我们参数中有些还设置的 -Xss=256k 是早期设置 的,现在已经不太合理7) 在 64 位 jvm ,设置 Xss 时提示最少要 104k9) Xss 并不是每个线程启动后都立刻分配了指定大小的栈空间的,否则 jvm 中若有 1000 个线程,按默认每个 1m ,仅线程栈就会占用 1G 内 存。
    29. 29. 对象的消亡► 前提,了解引用类型  强引用 ( 默认 )  软引用 (soft reference)  弱引用 (weak reference)  幽灵引用 (phantom reference)► 为什么引入另外三种 Reference ? 程序与 GC 有了交互方式
    30. 30. 对象的消亡: reference reachable强可达 strong reachable 线程根引用 强引用 C A 强引用 软引用 B B 不会被 GC 回收
    31. 31. 对象的消亡: reference reachable软可达 soft reachable 线程根引用 软引用 软引用 C A 软引用 D 软引用 强引用 B 内存不足时, B 会被 GC 回收 SoftRef 的存活时间 /M 空闲空间: -XX:SoftRefLRUPolicyMSPerMB 默认 1秒
    32. 32. 对象的消亡: reference reachable弱可达 weak reachable 线程根引用 弱引用 弱引用 C A 弱引用 D 弱引用 强引用 B GC 触发时 B 会被回收
    33. 33. 对象的消亡: ReferenceQueue 监听器 eg1 : 对 FinalReference 类型 ref 计数,执行其 finalize 方法 pending 链表 ReferenceQueueGC next pending ReferenceQueue ReferenceQueue discovered ref ReferenceHandler 线程负责轮询 pending 链表, 根据 queue 的类型决定是否将 元素放入 queue
    34. 34. ReferenceQueue 的案例► 从这篇帖子说起 “WeakHashMap 的神话” : http://www.javaeye.com/topic/587995结合 WeakHashMap 的代码,分析一下作者的问题
    35. 35. 对象的消亡: finalize1) JVM 中存在的两个 daemon 线程 java.lang.ref.Finalizer$FinalizerThread 消费者(处理出队的元素)java.lang.ref.Reference$ReferenceHandler 生产者(入队)2) 对象实现 finalize 方法需要 2 次 GC 才能回收 所有实现了 finalize 方法的对象会被封装为 FinalReference ,第一次 gc 时被放入 ReferenceQueue 确保 finalize 方法被执行,第二次 gc 才真正被收集 jmap -finalizerinfo javapid 显示在 F-Queue 中等待 Finalizer 线程执行 finalize 方法的对象。3) finalize 导致对象复活 幽灵引用的用途
    36. 36. 类的消亡:卸载 Class1) 系统 classloader 加载的 Class 不会被卸载只有非系统 classloader 加载的 Class 才有可能 被卸载。2) Class 若有 static field 或 static block ,卸载 时除了没有可达引用,还需要其 classloader 也没有被使用才行。 Why ? 假设可以被卸载,当需要重新加载时, static field 被重新初始化,其 状态可能与之前不一致; static 构造块也会重新执行,与预期不一致, 或许引起副作用。
    37. 37. 类的消亡: Perm Gen 的泄漏► Classloader 泄漏 Classloader1 Classloader2 C.class D.class A.class 实例 B.class a用于动态加载的 classloader1 是 classloader2 的 child , A 实例化时注册到了 B 静态成员中,形成上面的情况, classloader1 及其加载的所有类都不会被卸载参考此例: http://frankkieviet.blogspot.com/2006/10/classloader-leaks-dreaded-permgen-space.html
    38. 38. 第二部分GC 的选择,以及 CMS GC 详解
    39. 39. GC 的选择 (G1 除外 )► -XX:+UseSerialGC 采用 Serial + Serial Old 组合 , client 模式默认是此方式► -XX:+UseParallelGC 采用 Parallel Scavenge + Serial Old(PS MarkSweep) 组合, server 模式默认► -XX:+UseParNewGC 采用 ParNew + Serial Old 组合► -XX:+UseParallelOldGC 采用 Parallel Scavenge + Parallel Old 组合► -XX:+UseConcMarkSweepGC 采用 ParNew + CMS + Serial Old(CMS 的备用 ) 组合► -XX:+UseConcMarkSweepGC -XX:-UseParNewGC 采用 Serial + CMS + Serial Old(CMS 的备用 ) 组合
    40. 40. GC 的选择:新生代与旧生代的组合 吞吐量优先 可自适应调节 新生代各区域 Jdk1.4 提供 Parallel Serial ParNew Scavenge CMSJdk1.5 Parallel Old 提供 Serial/ PS MarkSweep 作为 CMS 的备 份,在 CMS 并 PS 的旧生代版本 发失败时采用 Jdk1.6 提供
    41. 41. GC 的选择: -XX:+UseSerialGC采用 Serial + Serial Old 组合 , client 模式默认是此方式 Parallel Serial ParNew Scavenge Serial/ CMS Parallel Old PS MarkSweep
    42. 42. GC 的选择: -XX: +UseParallelGC采用 Parallel Scavenge + Serial Old(PS MarkSweep) 组合, server 模式默认 Parallel Serial ParNew Scavenge Serial/ CMS Parallel Old PS MarkSweep
    43. 43. GC 的选择: -XX: +UseParNewGC采用 ParNew + Serial Old 组合 Parallel Serial ParNew Scavenge Serial/ CMS Parallel Old PS MarkSweep
    44. 44. GC 的选择: -XX:+UseParallelOldGC 采用 Parallel Scavenge + Parallel Old 组 合 Parallel Serial ParNew Scavenge Serial/ CMS Parallel Old PS MarkSweep
    45. 45. GC 的选择: -XX: +UseConcMarkSweepGC采用 ParNew + CMS + Serial Old(CMS 的备用 ) 组 合 Parallel Serial ParNew Scavenge CMS Serial/ Parallel Old 备用 PS MarkSweep
    46. 46. GC 的选择: -XX: +UseConcMarkSweepGC -XX:- UseParNewGC采用 Serial+ CMS + Serial Old(CMS 的备用 ) 组合 Parallel Serial ParNew Scavenge CMS Serial/ Parallel Old 备用 PS MarkSweep
    47. 47. GC 的选择:策略依据► 从应用场景: 1) web app ,用户响应优先; 2) 任务,吞吐率优先► 从成熟度和稳定性 生产环境选择一种策略前需要大量测试
    48. 48. Minor GC► young generation eden S0 S1 1) Survivor 区大小可通过 -XX:SurvivorRatio 来设置 , CMS GC 默认为 8 即 -Xmn=500m 的话, eden 占 80% 为 400m , s0 和 s1 各 10% 为 50m 2) 可通过 – XX:MaxTenuringThreshold=X 设置对象经历多少次 minor gc 才进入旧生代,并行 GC 默认 15 , CMS GC 默认为 4 3) 为什么采用 2 个 Survivor 区域?因为该区 gc 主要采用拷贝算法
    49. 49. Minor GC , copying 算法 from to[admin@exodus-web2244 ~]$ jstat -gcutil 22063 1000 S0 S1 E O P YGC YGCT FGC FGCT GCT 21.30 0.00 3.29 34.34 68.37 71190 1450.721 20 1.451 1452.173 21.30 0.00 32.18 34.34 68.37 71190 1450.721 20 1.451 1452.173 21.30 0.00 64.86 34.34 68.37 71190 1450.721 20 1.451 1452.173 0.00 18.42 6.02 34.35 68.37 71191 1450.751 20 1.451 1452.202 0.00 18.42 41.07 34.35 68.37 71191 1450.751 20 1.451 1452.202 0.00 18.42 68.41 34.35 68.37 71191 1450.751 20 1.451 1452.202 22.26 0.00 4.08 34.35 68.37 71192 1450.771 20 1.451 1452.222 22.26 0.00 49.14 34.35 68.37 71192 1450.771 20 1.451 1452.222 22.26 0.00 79.94 34.35 68.37 71192 1450.771 20 1.451 1452.222 to from
    50. 50. Major GC► 只分享 CMS GC► CMS GC 与 Full gc 是一回事么?
    51. 51. CMS GC 的详细过程 ① ② ③ ④ concurrent final concurrent用户线程 preclean initial marking marking sweeping marking 用户线程 用户线程 safepoint safepointstop-the-world stop-the-world 两次 stop-the-world ,这也是为什么 jstat –gcutil 看到 FGC 次数每次增长为 2 (current mode failure 的情况另说 )
    52. 52. CMS GC 的详细过程① Initial marking Root Set仅标记根集合直接可达对象 , A1 B1 C1 D1记录在外部的 bitmapto-be-scanned A3 B2 A2 A4
    53. 53. CMS GC 的详细过程② Concurrent marking Root Set A1 B1 C1 D1 marking 的过程即 遍历所有对象,进 行着色, A3 B2 借助 markingStack 栈完成遍历, 最费时的一个过程 A2 可通过下面参数设置其大小 -XX:CMSMarkStackSize=xxx ( 默认 32k) -XX:CMSMarkStackSizeMax=yyy A4 ( 默认 4M) 采用栈的方式,就有栈溢出的可能 ,不过实际过程有很多技巧,未探 究
    54. 54. CMS GC 的详细过程② Concurrent marking 此过程 minor gc 和用户线程也是可以工作的; 怎么应对 minor gc 和用户线程对数据修改不一致 ? Heap Card Table Mod Union Table 划分为多个区域 (card) ,如果该区 域用户线程改变数据发生不一致 记录 minor gc (dirty) ,则记录在 card table 中 修改的 card
    55. 55. CMS GC 的详细过程② preclean 新增的一个优化步骤,减少下一阶段 (remark) stop-the-world 的时间 -XX:CMSMaxAbortablePrecleanTime=5000
    56. 56. CMS GC 的详细过程③ Final marking (stop-the-world) C D F A G B E 该区域对象发生 过变化 (dirty) 重新 marking
    57. 57. CMS GC 的详细过程④ Concurrent sweeping Sweeping 之后的碎片问题 Root A B C D E Set 对于碎片整理,可通过 对于 mark-swap 算法的 gc 另 -XX:UseCMSCompactAtFullCollection 一个不利是由于碎片的原因不 在每次 fullgc 时整理,也可使用 好使用 -XX:CMSFullGCsBeforeCompaction=X Bump-the-pointer 方式来分配 指定多少次 fullgc 后整理 内存 ( 适合于大片连续的空间 )
    58. 58. CMS GC 详情 : 浮动垃圾► 浮动垃圾的产生 图中的对象 c 为浮动垃圾,需要等下次 gc 才能回收。 http://research.sun.com/techrep/2000/smli_tr-2000-88.pdf
    59. 59. CMS GC 详情 : PLABsPromotion local allocation buffers (PLABs)在新生代,并发收集时,对象将可能从 eden 晋升到 survivor 区,或老生代。在 survivor 或 old 区为晋升的对象分配空间时为了避免多线程竞争,对每个线程分配了缓冲区,在 survivor 区每个线程有一个 PLAB ,在 old 区每个线程也有一个PLAB但在 survivor 区域,可用空间是连续的 ( 拷贝算法,总有一个 survivor 会空出来 ) ,所以 PLAB 也是连续的,而 old 区的空间则可能是非连续的 (cms 产生的碎片 ) ,所以 PLAB 可能通过一些手段组织一些非连续的空间对比一下 TLABs ,意图一样,不过情况复杂一些。-XX:+PrintOldPLAB
    60. 60. CMS GC 详情 : 触发► CMS GC 的触发:1: 旧生代空间使用到一定比率 -XX:CMSInitiatingOccupancyFraction=XX Jdk6 默认 92%2: perm gen 采用 CMS 且空间使用到一定比率 perm gen 采用 CMS 收集需设置: -XX:+CMSClassUnloadingEnabled 可通过 -XX:CMSInitiatingPermOccupancyFraction 来指定 Jdk6 默认为 92%3: System.gc ,且设置了 ExplicitGCInvokesConcurrent4: JVM 根据情况自行判断 ( 启发式 ) 决定是否进行 cms 基于对 promotion 的统计,自行决定是否需要 可通过 -XX:+UseCMSInitiatingOccupancyOnly 禁止启发式执行 cms gc
    61. 61. CMS GC 详情 : 触发► CMS GC 的触发 :1: 旧生代空间使用到一定比率 (CMSInitiatingOccupancyFraction) JDK6 默认 92%[wei@vm-qa-cn-141-155 whj]$ jstat -gcutil 18592 2000 S0 S1 E O P YGC YGCT FGC FGCT GCT0.00 16.13 16.21 91.93 98.31 9635 127.704 0 0.000 127.7040.00 17.43 13.38 91.94 98.31 9651 127.926 0 0.000 127.92622.38 0.00 62.11 34.40 86.32 9668 128.144 2 0.123 128.2670.00 22.61 57.11 34.47 86.32 9685 128.353 2 0.123 128.47615.44 0.00 6.86 34.54 86.32 9702 128.586 2 0.123 128.708
    62. 62. CMS GC 详情 : 触发► CMS GC 的触发 :2: perm gen 采用 CMS 且空间使用到一定比率$ scala -J-XX:PermSize=40M -J-XX:MaxPermSize=40M -J-XX:+UseConcMarkSweepGC -J- Xms1g -J-Xmx1g -J-XX:+CMSClassUnloadingEnabledscala > :cp /data/tmp/demo/scala > :load /data/tmp/demo/import开启 CMSClassUnloadingEnabled , perm gen 达到 92% 触发 cms gc S0 S1 E O P YGC YGCT FGC FGCT GCT83.19 0.00 6.62 4.28 90.86 16 0.425 0 0.000 0.425 0.00 84.85 80.56 4.45 91.74 19 0.451 0 0.000 0.45185.31 0.00 0.00 4.72 92.17 24 0.495 3 0.048 0.54392.21 0.00 0.00 4.95 93.03 28 0.529 6 0.127 0.65686.89 0.00 50.94 5.18 93.91 32 0.558 10 0.171 0.728
    63. 63. CMS GC 详情 : 触发► CMS GC 的触发 :3: 调用 System.gc 且启用 ExplicitGCInvokesConcurrent$ scala -J-XX:+UseConcMarkSweepGC -J-Xms1g -J-Xmx1g -J-XX:+ExplicitGCInvokesConcurrentscala > System.gc注,这里仍用 jstat –gcutil 来观察, FGC=2 表示一次 CMS GC ,这不太严禁,可以 用 GC log 来观察 S0 S1 E O P YGC YGCT FGC FGCT GCT0.00 0.00 93.83 0.00 99.46 0 0.000 0 0.000 0.0000.00 0.00 95.85 0.00 99.46 0 0.000 0 0.000 0.00089.95 0.00 0.00 1.93 60.00 2 0.199 2 0.003 0.20289.95 0.00 2.08 1.91 60.15 2 0.199 2 0.003 0.202
    64. 64. CMS GC 详情:触发 Full GC►Full GC(Serial) 的触发:1: Concurrent-mode-failure & Promotion-mode- failure2: perm gen 未启用 CMSClassUnloadingEnabled 在 100% 时触发 full-gc3: System.gc , ( 且未启用 ExplicitGCInvokesConcurrent) 可通过 -XX:+DisableExplicitGC 来禁止显式 gc
    65. 65. CMS GC 详情:触发 Full GC Full GC(Serial) 的触发 : Concurrent mode failure 是怎么回事? X No more spaceYoung gen old gen 对象从新生代晋升到旧生代时,需要确保旧生代有足够的内存容纳新 晋升的对象。 CMS 收集器通过统计以前的分配来预估新晋升对象的大 小,如果旧生代空间小于预估对象大小,即导致 concurrent-mode-failure ;此时会采用 CMS 的备份策略 (Serial GC) 常见的 concurrent-mode-failure 是 CMS 周期初始化太迟 ( 对象太多, 剩余空间不足 ) 所致
    66. 66. CMS GC 详情:触发 Full GC Full GC(Serial) 的触发 : Promotion failure 是怎么回事? XYoung gen old gen 对象从新生代晋升到旧生代时,由于碎片的原因,尽管总的可用空间 可能比新晋升的对象要大,但因没有连续的空间能分配给晋升对象, 导致无法晋升,触发 Full GC(Serial)
    67. 67. CMS GC 详情:触发 Full GC► Full GC(Serial) 的触发 :2: perm gen 不采用 cms 的话,在快 100% 时触发 full gc ( 不是 cms gc)$ scala -J-XX:MaxPermSize=45M -J-XX:+UseConcMarkSweepGC -J-Xms1g -J-Xmx1gscala > :cp /data/tmp/demo/scala > :load /data/tmp/demo/import没有开启 CMSClassUnloadingEnabled , perm gen 几乎 100% 才触发 full gc S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 84.21 94.98 4.74 98.97 25 0.500 0 0.000 0.50089.77 0.00 56.99 5.03 99.39 30 0.540 0 0.000 0.54085.32 0.00 6.95 5.14 85.56 34 0.556 1 0.356 0.912 0.00 71.05 10.33 5.44 86.40 39 0.590 1 0.356 0.946
    68. 68. CMS GC 详情:触发 Full GC► Full GC(Serial) 的触发 :3: System.gc ( 未启用 ExplicitGCInvokesConcurrent)$ scala -J-XX:+UseConcMarkSweepGC -J-Xms1g -J-Xmx1gscala > System.gc注,这里仍用 jstat –gcutil 来观察, FGC=1 表示一次 Full GC ,这不太严禁,可以 用 GC log 来观察 S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 0.00 93.87 0.00 99.46 0 0.000 0 0.000 0.000 0.00 0.00 95.89 0.00 99.46 0 0.000 0 0.000 0.000 0.00 100.00 9.60 1.51 99.36 1 0.169 1 0.000 0.169 0.00 0.00 2.10 1.78 60.15 1 0.169 1 0.207 0.376 0.00 0.00 2.10 1.78 60.15 1 0.169 1 0.207 0.376
    69. 69. 第三部分业务线配置参考
    70. 70. 看看业务线用的配置 ► B2B 中文站 (OracleJDK 1.6.0_25) : 25% 64 位默认是 1024k -Xmx2g -Xms2g -Xmn512m -Xss256k -XX:PermSize=128m -XX:MaxPermSize=196m 注意 -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC Jdk6 默认 -XX:+CMSParallelRemarkEnabled 已开启 -XX:+UseCMSCompactAtFullCollection Jdk7 默认 -XX:+UseCompressedOops 关闭 -XX:+UseFastAccessorMethods 禁止 jvm 启发 -XX:+UseCMSInitiatingOccupancyOnly 式 触发 cms 。未指定: CMSInitiatingOccupancyFraction jdk6 默认 92% 注意 concurrent-mode-failure
    71. 71. 看看业务线用的配置► 淘宝 ( 交易 ) OpenJDK 64-Bit : 40% -Xms4g -Xmx4g -Xmn1600m 注意场景 -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+ExplicitGCInvokesConcurrent Jdk6 默认 -XX:+UseConcMarkSweepGC 已开启 -XX:+UseCMSCompactAtFullCollection -XX:+CMSParallelRemarkEnabled Jdk6 已废 弃 -XX:+CMSPermGenSweepingEnabled 不需要 -XX:+CMSClassUnloadingEnabled 注意场景 -XX:+UseCMSInitiatingOccupancyOnly 待分析 -XX:CMSInitiatingOccupancyFraction=82 -XX:+HeapDumpOnOutOfMemoryError 不启用 -XX:-UseCompressedOops 指针压缩 … 其它省略
    72. 72. 看看业务线用的配置► 天猫 (tmallsell) 62.5% -Xms4g -Xmx4g -Xmn2560m -XX:PermSize=96m -XX:MaxPermSize=256m -XX:SurvivorRatio=10 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSMaxAbortablePrecleanTime=5000 -XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+DisableExplicitGC -XX:+AggressiveOpts 其他省略
    73. 73. 看看业务线用的配置► 天猫 (malllist) 50% 2 倍默认 -Xms4g -Xmx4g -Xmn2000m -Xss2m -XX:PermSize=256m -XX:MaxPermSize=320m -XX:SurvivorRatio=10 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSMaxAbortablePrecleanTime=5000 -XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+DisableExplicitGC 其他省略
    74. 74. 看看业务线用的配置► 阿里金融 ( 贷款业务 ) 系统内存的 deployMem=`echo "$MEM*6/10" | bc`m 3/5 -Xms${deployMem} -Xmx${deployMem} 最好也用变量 -Xmn1536m 来表达 -XX:PermSize=256M -XX:MaxPermSize=256M -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:+DisableExplicitGC 其他省略
    75. 75. 看看业务线用的配置 Jdk1.4 之后► 支付宝 ( 某 SOA 服务 ) Deprecated. 用 -Xmn 替代 -Xms768m -Xmx1280m -XX:PermSize=96m -XX:MaxPermSize=128m -XX:NewSize=128m -XX:MaxNewSize=128m -XX:SurvivorRatio=20000 Deprecated. -XX:+UseParNewGC 注意场景。适用于 CPU 资源紧张或应用 -XX:+UseConcMarkSweepGC cpu 负载较高的情况, -XX:+UseCMSCompactAtFullCollection 一般单 cpu 才考虑, -XX:+CMSIncrementalMode 默认不开启 . 可能该服 -XX:+CMSPermGenSweepingEnabled 务器上部署了多个实例 -XX:CMSInitiatingOccupancyFraction=1 -XX:CMSFullGCsBeforeCompaction=0 会频繁 gc? -XX:CMSIncrementalDutyCycleMin=10 默认就是 0 -XX:CMSIncrementalDutyCycle=30 -XX:CMSMarkStackSize=8M 增量模式参数 -XX:CMSMarkStackSizeMax=32M -XX:MaxTenuringThreshold=0 其他省略 0 表示不经过 Survivor 直接进 入老生代
    76. 76. 看看业务线用的配置► 良无限 12.5% -Xms2g -Xmx2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70
    77. 77. 看看业务线用的配置► 阿里云 ( 邮箱 ) 12.5% -Xmx2g -Xms2g -Xmn256m -Xss256k -XX:PermSize=128m -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70
    78. 78. 引用 & 推荐博客 :http://blog.ragozin.info/2011/06/understanding-gc-pauses-in-jvm-hotspots.htmlhttp://frankkieviet.blogspot.com/2006/10/classloader-leaks-dreaded-permgen-space.htmlhttps://blogs.oracle.com/poonam/entry/understanding_cms_gc_logshttps://blogs.oracle.com/jonthecollector/entry/the_real_thinghttp://stackoverflow.com/questions/7065337/intern-behaving-differently-in-jdk6-and-jdk7http://javaeesupportpatterns.blogspot.com/2011/10/java-7-features-permgen-removal.htmlhttp://blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead/http://hllvm.group.iteye.com/group/topic/27945http://embedded.soe.ucsc.edu/pubs/sigplan98-1/short.htmlhttp://rednaxelafx.iteye.com/blog/书籍 :《深入 java 虚拟机》《分布式 Java 应用:基础与实践》《垃圾收集》

    ×