Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
JAVA 垃圾收集原理 @gongyin [email_address]
 
“ Garbage collection  ( GC ) is a form of automatic  memory management . The  garbage collector , or just  collector , attempts to reclaim  garbage , or memory occupied by  objects  that are no longer in use by the  program   ”   - Wikipedia
自动内存管理年代 还有必要学习和了解 GC ?
垃圾收集器做什么? 释放非存活对象占据的内存空间 管理内存,决定了内存分配机制
垃圾收集器如何做? 检测出垃圾对象 直接方式:引用计数 间接方式 :  追踪对象引用图 回收垃圾对象所占用的内存空间 直接清除 压缩 拷贝 必须决定什么时候进行回收
垃圾算法的基本要求 必须是安全的,存活数据不能被错误回收 应该是全面的,垃圾对象会在固定的收集周期被回收 应该有合理的开销,时间 / 空间 / 运行频率 尽可能少的内存碎片 应该是可扩展的,不会成为可扩展瓶颈
常用的 GC 算法和策略 引用计数器(渐进式) 标记 - 清扫垃圾收集 节点复制垃圾收集 标记 - 缩并垃圾收集 分代垃圾收集 并发垃圾收集 分布式垃圾收集 自适应动态垃圾收集
引用计数器 Pros 实现简单,能快速判断对象是否在使用 交织在程序中执行,不会挂起应用 Cons 无法处理循环引用 给程序执行带来额外的开销 与用户程序紧密的耦合
标记 - 清扫算法 Pros 非常自然的处理环形结构 操纵指针没有额外的 开销 Cons 停止 - 启动 算法, STW 问题 内存碎片问题 渐进复杂度正比与堆的大小
节点复制算法 Scavenger 清道夫,从垃圾中捡起有价值的并带走 Pros 所有存活的数据都缩并的排列在一起 无内存碎片,能够高效的分配对象 Cons 使用两个半区,存储容量加倍 重复拷贝 性能随着内存占用率提高而下降,复杂度正比于存活数据结构的大小,而不是堆的大小
标记 - 缩并算法 缩并方式 任意的 / 线性的 / 滑动的 Pros 不需要占用额外空间 Cons 缩并带来性能损失 渐进复杂度类似与节点复制算法
分代式垃圾收集器 Weak generational hypothesis 理论 大部分对象都是短暂的,生命周期很短 只有很少的长生命对象会引用短生命对象 把工作集中在回收最有可能是垃圾的对象上 Pros 不同的分代可以使用不同的算法和不同的搜集频率,能减少垃圾收集的整体开销 Cons 如果根集合巨大 分代间引用  以及 占位垃圾  问题
分代式垃圾收集器 需要合理设置  提升策略  和 提升阀值 提升太快 Major GC 占位垃圾 和 庇护现象 程序的局部性有负面影响,工作集稀疏 增大写拦截器的开销 自适应提升策略 在缩短中断时间和占位垃圾之间进行折衷 调度策略 隐藏在用户最不注意到时刻 最多垃圾时触发
渐进式和并发收集器 三色标记  已访问 需重访问 未访问 Pros 大幅缩短垃圾收集带来的中断时间 Cons 吞吐量,垃圾收集总耗时上升 “ 多个读,多个写”一致性问题,需要和用户程序同步,漂浮垃圾问题 需提前进行收集,可能并发收集失败
自适应垃圾收集算法 监视服务器和应用情况,自动调整和选择合适的收集算法 JAVA 中的 Eronomic
Java 基于分代策略 每个分代可以使用不同的垃圾收集器
Java 基于分代垃圾收集策略
Java 中如何检测垃圾对象的? 找到 GC Root 集合 本地变量和局部变量引用的对象 方法区中类静态属性引用的对象 方法区中常量引用的对象 本地方法栈中 JNI 所引用的对象 跨分区引用的对象,分代间引用 引用对象被提升 被重新赋值指向新生分代对象
Java 中如何检测垃圾对象的? 写拦截器 Write-barrier Dirty Card JVM 维护一个 dirty cards  表 每 512 byte 内存页关联到一个 dirty card 内存页发生变化,则标记 dirty page GC 完成,重设 dirty card Snapshot-at-the-beginning (SATB)  G1
Java 中如何检测垃圾对象的? 根据对象存活状态( Reachable )标记出垃圾对象 强引用 软引用( SoftReference ) -XX:SoftRefLRUPolicyMSPerMB 弱引用 (WeakReference) 可复活对象 被 finalize 方法复活 ( 需两遍扫描 ) 虚引用 (PhantomReference) 对象被回收时得到系统通知  ReferenceQueue 不可达对象
垃圾清扫阶段 释放被占用的垃圾 非压缩,直接释放 清道夫复制 滑动缩并
新对象分配 直接分配在新生代 Eden 或 TLAB TLAB  thread local allocation block -XX:+PrintTLAB  -XX:+UseTLAB  -XX:+ResizeTLAB  -XX:TLABSize=<size>  -XX:MinTLABSize=<size>  大对象和大数组直接分派在旧生代 -XX:PretenureSizeThreshold= n   如果对象大于 Eden 大小 堆外分配 DirectByteBuffer Unsafe.allocateMemory -XX:MaxDirectMemorySize=<value>
对象提升策略 -XX:+AlwaysTenure   ,直接从新生代到旧生代 Survivor 区域满后,其他存活对象提升 对象已经存活一定次数的收集周期 – XX:MaxTenuringThreshold   – XX:TargetSurvivorRatio
垃圾收集器性能度量指标 吞吐量 throughput 没有花在 GC 上的时间百分比,比如 GC 花了 1% 的时间,那么吞吐量是 99% GC 负载 GC Overhead 停顿时间 pause Time 新生代暂停时间  =  栈扫描时间 +DirtyCard 扫描时间 + 旧生代扫描时间 + 存活对象赋值时间 垃圾收集器执行的频率 内存大小 Footprint 敏捷性 Promptness 对象变成垃圾和此块内存可以被利用的时间
Java 提供 4 种类型的 GC Serial Collector   – XX :+UseSerialGC Parallel Collector  – XX:+UseParallelGC  Parallel Compacting Collector(1.5R6) – XX:+UseParallelOldGC CMS Collector – XX:+UseConcMarkSweepGC
串行收集器 STW – XX:+UseSerialGC 新生代使用串行 GC 旧生代和持久代也使用串行 GC 适用于小内存客户端应用
并行收集器 STW – XX:+UseParallelGC Parallel 新生代使用并行复制收集算法 旧生代使用并行压缩 mark-sweep-compacting – XX:+UseParallelOldGC – XX:ParallelGCThreads= n
并发收集器 过程 Initial mark ,STW, 收集 GC Roots 栈 新生代对象应用旧生代对象 速度依赖于新生代存活对象的多少  – XX:CMSWaitDuration= n Concurrent Mark ,标记存活对象 Concurrent pre clean, 统计被改变的引用 Remark , STW ,重新标记被改变的引用   – XX:+CMSScavengeBeforeRemark // 强制新生代 GC Concurrent sweep Concurrent  reset
并发收集器 – XX:+UseConcMarkSweepGC 不会压缩堆,不同大小碎片有各自的 free memory list – XX:+CMSIncrementalMode – XX:ParallelGCThreads=n 何时触发 最好在新生代 GC 之后 ‑ XX:+UseCMSInitiatingOccupancyOnly = ‑ XX:+ExplicitGCInvokesConcurrent  导致 Full   GC 并行模式问题 Concurrent mode failure 正在执行 CMS ,但是没有足够的空间分配给新对象 提升失败问题 Promotion failure 提升的对象太多,旧生代放不下
并发收集器 针对多核优化参数 ‑ XX:+CMSConcurrentMTEnabled  并发阶段使用多核 ‑ XX:+ConcGCThreads=  ‑ XX:+ParallelGCThreads=  STW 阶段并行线程数目,默认 CPU 数目 ‑ XX:+UseParNewGC  新生代使用并行复制算法 限制 对 CPU 资源敏感 漂浮垃圾问题 内存碎片问题 ‑ XX:+UseCMSCompactAtFullCollection  ‑ XX:+CMSFullGcsBeforeCompaction =
Garbge First G1  ( jdk16.R14 ) 基于 标记 - 压缩算法 可以精准的控制暂停时间 将 Heap 分为多个大小的独立区域 G1 维护优先列表,检测哪个区域内存使用最快,然后仅仅收集此区域 清除空区域代价很小 复制小数量的对象很快
GC  组合 Young collector Old collector JVM option Serial (DefNew) Serial Mark-Sweep-Compact -XX:+UseSerialGC Parallel scavenge (PSYoungGen) Serial Mark-Sweep-Compact (PSOldGen) -XX:+UseParallelGC Parallel scavenge (PSYoungGen) Parallel Mark-Sweep-Compact (ParOldGen) -XX:+UseParallelOldGC Serial (DefNew) Concurrent Mark Sweep -XX:+UseConcMarkSweepGC -XX:-UseParNewGC Parallel (ParNew) Concurrent Mark Sweep -XX:+UseConcMarkSweepGC -XX:-UseParNewGC G1 -XX:+UseG1GC
Ergonomics 基于平台和操作系统自动选择 collertor 、 heap size 和 hotspot client or server 目标是提供尽可能好的性能而不需要设置太多命令参数,自动化
Behavior-based parallel 最大停顿时间 -XX : MaxGCPauseMillis=n 最大吞吐量 -XX : GCTimeRatio=n Ratio = 1/ ( 1+N ) Default value = 1% 缺省优先级:先满足停顿时间,然后吞吐量,最后 footprint
一些常用配置 单处理器系统或小内存, 100M 左右内存 -XX:+UseSerialGC     多处理器系统,需要最大吞吐量不关心暂停时间 -XX:+UseParallelGc  -XX:+UseParallelOldGC  最小停顿时间 -XX:+UseConcMarkSweepGC  -XX:+ParNewGC,  有内存碎片,内存越大越好   
优化原则 Do Nothing, 让 JVM 自动选择 不存在一个简单而普适的原则,必须充分理解系统的需求和特征 先 measure ,在 tune 不要过度 tune 需要在各个指标之间进行权衡
常用监控和分析工具 GC 参数 -XX : +PrintGCDetails -XX:  +PrintHeapAtGC  -XX : +PrintGCTimeStamps -XX:+HeapDumpAfterFullGC -XX:+HeapDumpBeforeFullGC -XX:+HeapDumpOnOutOfMemoryError Jmap –histo | -heap | -permstat Jstat Jconsole VisualVM HAT : Heap Analysis Tool
References http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html http://java.sun.com/performance/reference/whitepapers http://www.oracle.com/technetwork/java/faq-140837.html http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#PerformanceTuning http://blogs.oracle.com/jonthecollector/entry/our_collectors http://java.sun.com/docs/hotspot/VMOptions.html
Thank you
 
 

More Related Content

Java垃圾收集原理