java 程序 jvm 垃圾回收算法 收集器 和 内存溢出
1.垃圾回收算法(GC,Garbage Collection)
红色是标记的非活动对象,绿色是活动对象。
标记-清除(Mark-Sweep)
GC 分为两个阶段,标记和清除。首先标记所有可回收的对象,在标记完成后统一回收所有被标记的对象。同时会产生不连续的内存碎片。
碎片过多会导致以后程序运行时需要分配较大对象时,无法找到足够的连续内存,而不得已再次触发GC。
复制(Copy)
将内存按容量划分为两块,每次只使用其中一块。当这一块内存用完了,就将存活的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。这样使得每次都是对半个内存区回收,也不用考虑内存碎片问题,简单高效。缺点需要两倍的内存空间。
标记-整理(Mark-Compact)
也分为两个阶段,首先标记可回收的对象,再将存活的对象都向一端移动,然后清理掉边界以外的内存。此方法避免标记-清除算法的碎片问题,同时也避免了复制算法的空间问题。
年轻代 和 老年代 收集方法:
一般年轻代中执行 GC 后,会有少量的对象存活,就会选用复制算法,只要付出少量的存活对象复制成本就可以完成收集。
而老年代中因为对象存活率高,没有额外过多内存空间分配,就需要使用标记-清理或者标记-整理算法来进行回收。
2. 垃圾收集器
串行收集器(Serial)
比较老的收集器,单线程。收集时,必须暂停应用的工作线程,直到收集结束。
并行收集器(Parallel)
多条垃圾收集线程并行工作,在多核CPU下效率更高,必须暂停应用的工作线程,直到收集结束。
CMS 收集器(Concurrent Mark Sweep)
CMS 收集器是缩短暂停应用时间为目标而设计的,是基于标记-清除算法实现。
整个过程分为 4 个步骤,包括:
初始标记(Initial Mark)
并发标记(Concurrent Mark)
重新标记(Remark)
并发清除(Concurrent Sweep)
其中,初始标记、重新标记这两个步骤仍然需要暂停应用线程。
初始标记只是标记一下GC Roots 能直接关联到的对象,速度很快
并发标记阶段是标记可回收对象
重新标记阶段则是为了修正并发标记期间因用户程序继续运作导致标记产生变动的那一部分对象的标记记录,这个阶段暂停时间比初始标记阶段稍长一点,但远比并发标记时间短。
由于整个过程中消耗最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以大大减少了暂停时间。
G1 收集器(Garbage First)
G1 收集器将堆内存划分多个大小相等的独立区域(Region),并且能预测暂停时间,能预测原因它能避免对整个堆进行全区收集。G1 跟踪各个 Region 里的垃圾堆积价值大小(所获得空间大小以及回收所需时间),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region,从而保证了在有限时间内获得更高的收集效率。
G1收集器工作工程分为4个步骤,包括:
初始标记(Initial Mark)
并发标记(Concurrent Mark)
最终标记(Final Mark)
筛选回收(Live Data Counting and Evacuation)
步骤内工作
初始标记 与 CMS 一样,标记一下 GC Roots能直接关联到的对象。
并发标记从 GC Root 开始标记存活对象,这个阶段耗时比较长,但也可以与应用线程并发执行。
最终标记也是为了修正在并发标记期间因用户程序继续运作而导致标记产生变化的那一部分标记记录。
筛选回收阶段对各个Region回收价值和成本进行排序,根据用户所期望的 GC 暂停时间来执行回收
3.垃圾收集器参数
4. 为什么会堆内存溢出?
在年轻代中经过 GC 后还存活的对象会被复制到老年代中。当老年代空间不足时,JVM会对老年代进行完全的垃圾回收(Full GC)。如果 GC 后,还是无法存放从 Survivor 区复制过来的对象,就会出现OOM(Out of Memory)。
OOM(Out of Memory)异常常见有以下几个原因:
老年代内存不足:java.lang.OutOfMemoryError:Javaheapspace
永久代内存不足:java.lang.OutOfMemoryError:PermGenspace
代码bug,占用内存无法及时回收。
OOM 在这几个内存区都有可能出现,实际遇到 OOM 时,能根据异常信息定位到哪个区的内存溢出。
可以通过添加个参数 -XX:+HeapDumpOnOutMemoryError,让虚拟机在出现内存溢出异常时 Dump 出当前的内存堆转储快照以便事后分析。
5. 参数设置例子
熟悉了JAVA内存管理机制及配置参数,下面是对JAVA应用启动选项调优配置:
JAVA_OPTS="-server -Xms512m -Xmx2g -XX:+UseG1GC -XX:SurvivorRatio=6 -XX:MaxGCPauseMillis=400 -XX:G1ReservePercent=15 -XX:ParallelGCThreads=4 -XX:ConcGCThreads=1 -XX:InitiatingHeapOccupancyPercent=40 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:../logs/gc.log"
设置堆内存最小和最大值,最大值参考历史利用率设置
设置 GC 垃圾收集器 为 G1
启用 GC 日志,方便后期分析
共 0 条评论