1、JAVA垃圾收集原理,gongyin ,“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?,垃圾收集器做什么?释放非存活对象占据的内存空间管理内存,决定了内存分配机制
2、,垃圾收集器如何做?检测出垃圾对象 直接方式:引用计数 间接方式: 追踪对象引用图 回收垃圾对象所占用的内存空间 直接清除 压缩 拷贝 必须决定什么时候进行回收,垃圾算法的基本要求 必须是安全的,存活数据不能被错误回收应该是全面的,垃圾对象会在固定的收集周期被回收应该有合理的开销,时间/空间/运行频率尽可能少的内存碎片应该是可扩展的,不会成为可扩展瓶颈,常用的GC算法和策略,引用计数器(渐进式) 标记-清扫垃圾收集 节点复制垃圾收集 标记-缩并垃圾收集 分代垃圾收集 并发垃圾收集 分布式垃圾收集 自适应动态垃圾收集,引用计数器,Pros实现简单,能快速判断对象是否在使用 交织在程序中执行,不会
3、挂起应用Cons 无法处理循环引用 给程序执行带来额外的开销 与用户程序紧密的耦合,标记-清扫算法,Pros 非常自然的处理环形结构 操纵指针没有额外的 开销Cons 停止-启动 算法,STW问题 内存碎片问题渐进复杂度正比与堆的大小,节点复制算法,Scavenger清道夫,从垃圾中捡起有价值的并带走 Pros 所有存活的数据都缩并的排列在一起 无内存碎片,能够高效的分配对象Cons 使用两个半区,存储容量加倍 重复拷贝性能随着内存占用率提高而下降,复杂度正比于存活数据结构的大小,而不是堆的大小,标记-缩并算法,缩并方式 任意的/线性的/滑动的Pros 不需要占用额外空间Cons 缩并带来性能
4、损失 渐进复杂度类似与节点复制算法,分代式垃圾收集器,Weak generational hypothesis理论 大部分对象都是短暂的,生命周期很短 只有很少的长生命对象会引用短生命对象 把工作集中在回收最有可能是垃圾的对象上 Pros 不同的分代可以使用不同的算法和不同的搜集频率,能减少垃圾收集的整体开销Cons 如果根集合巨大 分代间引用 以及占位垃圾 问题,分代式垃圾收集器,需要合理设置 提升策略 和提升阀值 提升太快 Major GC 占位垃圾 和 庇护现象 程序的局部性有负面影响,工作集稀疏 增大写拦截器的开销 自适应提升策略 在缩短中断时间和占位垃圾之间进行折衷 调度策略 隐藏在
5、用户最不注意到时刻 最多垃圾时触发,渐进式和并发收集器,三色标记 已访问需重访问未访问 Pros 大幅缩短垃圾收集带来的中断时间Cons 吞吐量,垃圾收集总耗时上升 “多个读,多个写”一致性问题,需要和用户程序同步,漂浮垃圾问题 需提前进行收集,可能并发收集失败,自适应垃圾收集算法,监视服务器和应用情况,自动调整和选择合适的收集算法JAVA中的Eronomic,Java,基于分代策略 每个分代可以使用不同的垃圾收集器,Java基于分代垃圾收集策略,Java中如何检测垃圾对象的?,找到GC Root集合 本地变量和局部变量引用的对象 方法区中类静态属性引用的对象 方法区中常量引用的对象 本地方法
6、栈中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:SoftRefLRUP
7、olicyMSPerMB 弱引用(WeakReference) 可复活对象 被finalize方法复活(需两遍扫描) 虚引用(PhantomReference) 对象被回收时得到系统通知 ReferenceQueue 不可达对象,垃圾清扫阶段,释放被占用的垃圾 非压缩,直接释放 清道夫复制 滑动缩并,新对象分配,直接分配在新生代Eden或TLAB TLAB thread local allocation block -XX:+PrintTLAB -XX:+UseTLAB -XX:+ResizeTLAB -XX:TLABSize= -XX:MinTLABSize= 大对象和大数组直接分派在旧生代
8、 -XX:PretenureSizeThreshold=n 如果对象大于Eden大小 堆外分配 DirectByteBuffer Unsafe.allocateMemory -XX:MaxDirectMemorySize=,对象提升策略,-XX:+AlwaysTenure ,直接从新生代到旧生代 Survivor区域满后,其他存活对象提升 对象已经存活一定次数的收集周期 XX:MaxTenuringThreshold XX:TargetSurvivorRatio,垃圾收集器性能度量指标,吞吐量throughput 没有花在GC上的时间百分比,比如GC花了1%的时间,那么吞吐量是99% GC负载
9、GC Overhead 停顿时间pause Time 新生代暂停时间 = 栈扫描时间+DirtyCard扫描时间+旧生代扫描时间+存活对象赋值时间 垃圾收集器执行的频率 内存大小Footprint 敏捷性Promptness对象变成垃圾和此块内存可以被利用的时间,Java提供4种类型的GC,Serial CollectorXX:+UseSerialGC Parallel Collector XX:+UseParallelGC Parallel Compacting Collector(1.5R6)XX:+UseParallelOldGC CMS CollectorXX:+UseConcMark
10、SweepGC,串行收集器,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 M
11、ark,标记存活对象 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:+Exp
12、licitGCInvokesConcurrent 导致Full GC 并行模式问题Concurrent mode failure 正在执行CMS,但是没有足够的空间分配给新对象 提升失败问题Promotion failure 提升的对象太多,旧生代放不下,并发收集器,针对多核优化参数 XX:+CMSConcurrentMTEnabled 并发阶段使用多核 XX:+ConcGCThreads= XX:+ParallelGCThreads= STW阶段并行线程数目,默认CPU数目 XX:+UseParNewGC 新生代使用并行复制算法 限制 对CPU资源敏感 漂浮垃圾问题 内存碎片问题 XX:+U
13、seCMSCompactAtFullCollection XX:+CMSFullGcsBeforeCompaction =,Garbge First,G1 (jdk16.R14) 基于 标记-压缩算法 可以精准的控制暂停时间 将Heap分为多个大小的独立区域 G1维护优先列表,检测哪个区域内存使用最快,然后仅仅收集此区域 清除空区域代价很小 复制小数量的对象很快,GC 组合,Ergonomics,基于平台和操作系统自动选择collertor、heap size和hotspot client or server目标是提供尽可能好的性能而不需要设置太多命令参数,自动化,Behavior-based
14、 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, 有内存碎片,内存越大越好,优化原则,
15、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:/ http:/ http:/ http:/ http:/ http:/ you,