jvm的垃圾回收和回收策略

垃圾收集算法

1.标记-清除算法 (Mark-Sweep)
分成标记和清除 两个阶段 :首先标记出所有需要回收的对象 标记完成后统一回收

  • 优点:简单
  • 缺点:效率问题 空间问题 会产生大量的不连续的内存碎片 分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾
    收集动作

2.复制算法(Copying)
原理:可用内存按容量划分为大小相等的两块,每次只使用一块 当使用完成了之后 将存活的对象复制到另外一块内存上,然后把以使用过的一次性删除

  • 优点:不要考虑内存碎片的复杂情况 只要推动堆顶指针 按顺序移动 简单 高效
  • 缺点:内存浪费一半代价太高
  • 目前的实现方式:一块较大的 Eden和两块较小的Survivor 默认是8:1:1 将Eden和Survivor 存活的对象复制到另外一个Survivor里面 如果不够使用老年代分配担保

3.标记-整理(Mark-Compact)
原理:(老年代) 先标记 然后让所有的存活的对象向一端移动 然后清理掉边界意外的内存

4.分代收集算法
原理:新生代 (复制算法) 老年代(标记-清除或标记-整理)

HotSpot算法实现

1.枚举根节点(GC Roots) GC Roots主要是在全局性的引用和执行上下文

  • 原理: 是使用一组称为OopMap的数据结构来达到这个目的的,在类加载完成的
    时候,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程中,也
    会在特定的位置记录下栈和寄存器中哪些位置是引用
0x026eb730:mov%eax,-0x8000(%esp)
…… ;ImplicitNullCheckStub slow case
0x026eb7a9:call 0x026e83e0 ;OopMap{ebx=Oop[16]=Oop off=142} ;*caload
(它指明了EBX寄存器和栈中
偏移量为16的内存区域中各有一个普通对象指针(Ordinary Object Pointer)的引用,有效范
围为从call指令开始直到0x026eb730(指令流的起始位置)+142(OopMap记录的偏移
量)=0x026eb7be,即hlt指令为止。)
;-java.lang.String:hashCode@48(line 1489)
;{runtime_call}
0x026eb7ae:push$0x83c5c18 ;{external_word}
0x026eb7b3:call 0x026eb7b8
0x026eb7b8:pusha
0x026eb7b9:call 0x0822bec0;{runtime_call}
0x026eb7be:hlt

2.安全点(Safepoint) 快速的完成枚举遇到的问题是(可能导致引用关系的变化)
HotSpot也的确没有为每条指令都生成OopMap,前面已经提到,只是在“特定的
位置”记录了这些信息,这些位置称为安全点(Safepoint),即程序执行时并非在所有地方都
能停顿下来开始GC,只有在到达安全点时才能暂停。

  • 安全点的选定基
    本上是以程序“是否具有让程序长时间执行的特征”为标准进行选定的——因为每条指令执行
    的时间都非常短暂,程序不太可能因为指令流长度太长这个原因而过长时间运行,“长时间
    执行”的最明显特征就是指令序列复用,例如方法调用、循环跳转、异常跳转等,所以具有
    这些功能的指令才会产生Safepoint。

3.安全区域(Safe Region)
使用Safepoint似乎已经完美地解决了如何进入GC的问题,但实际情况却并不一定。
Safepoint机制保证了程序执行时,在不太长的时间内就会遇到可进入GC的Safepoint。但是,
程序“不执行”的时候呢?所谓的程序不执行就是没有分配CPU时间,典型的例子就是线程处
于Sleep状态或者Blocked状态,这时候线程无法响应JVM的中断请求,“走”到安全的地方去
中断挂起,JVM也显然不太可能等待线程重新被分配CPU时间。对于这种情况,就需要安全
区域(Safe Region)来解决。

垃圾收集器(java -XX:+PrintCommandLineFlags -version)

1.Serial收集器
Serial/Serial Old收集器的运行过程。新生代采取复制算法 暂停所有线程 老年代采用标记整理算法暂停所有线程

2.ParNew收集器 ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之
外,其余行为包括Serial收集器可用的所有控制参数(例如:-XX:SurvivorRatio、-XX:
PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法、Stop The World、对
象分配规则、回收策略等都与Serial收集器完全一样

3.Parallel Scavenge收集器
Parallel Scavenge收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点
是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到
一个可控制的吞吐量(Throughput)。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总
消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),虚
拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。
可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数。
停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高
吞吐量则可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不
需要太多交互的任务。

4.CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集
器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重
视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常
符合这类应用的需求。

CMS收集器是基于“标记—清除”算法实现
的,它的运作过程相对于前面几种收集器来说更复杂一些,整个过程分为4个步骤,包括:

  • 初始标记(CMS initial mark)
  • 并发标记(CMS concurrent mark)
  • 重新标记(CMS remark)
  • 并发清除(CMS concurrent sweep)
    其中,初始标记、重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只是
    标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC RootsTracing
    的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变
    动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远
    比并发标记的时间短。
    缺点:
  • CMS收集器对CPU资源非常敏感。
  • CMS收集器无法处理浮动垃圾(Floating Garbage),可能出现“Concurrent Mode
    Failure”失败而导致另一次Full GC的产生。
  • CMS是一款基于“标记—清除”算法实现的收集
    器,如果读者对前面这种算法介绍还有印象的话,就可能想到这意味着收集结束时会有大量
    空间碎片产生。

5.G1收集器

  • G1是一款面向服务端应用的垃圾收集器。
  • 并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU(CPU或者
    CPU核心)来缩短Stop-The-World停顿的时间,部分其他收集器原本需要停顿Java线程执行的
    GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。
  • 分代收集:与其他收集器一样,分代概念在G1中依然得以保留。
  • 空间整合:与CMS的“标记—清理”算法不同,G1从整体来看是基于“标记—整理”算法实
    现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,但无论如何,这
    两种算法都意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种
    特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一
    次GC。
  • 如果不计算维护Remembered Set的操作,G1收集器的运作大致可划分为以下几个步骤:
    初始标记(Initial Marking)
    并发标记(Concurrent Marking)
    最终标记(Final Marking)
    筛选回收(Live Data Counting and Evacuation)
理解GC日志

在这里插入图片描述

  • [Full GC (System) Full表示GC日志的类型,System表示调用了System.gc()产生的
  • [DefNew [Tenured [Perm 表示GC发生的区域(GC收集器密切相关)后面的"3324K->152K(3712K)" 含义是 GC前改内存区域使用的容量->GC后该内存区域的容量(该内存区域的总容量) 后面的时间是该区域回收的时间 单位是秒
    再后面的 “3324K->152K(11904K)” GC前java堆已使用的容量->GC后java堆已使用的容量(java堆的总容量)
  • [Times: user=0.01 sys=0.00, real=0.02 secs] 分别表示用户消耗cpu的时间 内核消耗cpu的时间 开始到结束的时间
垃圾收集器参数总结

在这里插入图片描述

内存分配与回收策略
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值