JVM内存区域和垃圾回收

JVM内存区域

在讲述jvm垃圾回收之前,我们先介绍一下jvm的内存区域划分,主要分为以下五块:

  • 程序计数器
  • 虚拟机栈
  • 本地方法栈
  • 方法区
  • 堆内存
内存区域是否线程私有含义
程序计数器私有由于jvm多线程执行,所以每个线程需要记录线程执行到哪个字节码的位置,这样当线程获得cpu资源时才能知道从哪里继续执行
虚拟机栈私有虚拟机栈是java方法执行的内存模型,每个方法的执行就会创建一个栈帧,每个栈帧中包含了该函数的返回地址和局部变量。每个方法从调用到执行完毕,是一个入栈到出栈的过程,先入后出。虚拟机栈也是线程私有
本地方法栈私有和虚拟机栈类似,存放java中native方法
方法区共享存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。是所有线程共享区域
堆内存共享Java堆的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存

另外说明一下堆栈区别:

  • 栈是运行时单位,堆是存储单位
  • 栈代表的是运行逻辑,堆代表的是对象存储
  • 栈报错的是系统运行上下文,栈是向上增长,而堆可以动态伸缩
  • 栈中存放的是对对数据的引用,和基本数据类型

对象存活分析

在介绍jvm垃圾回收算法之前,我们需要明确什么样的对象才能被标注为垃圾;对象存活分析主要有两种分析方法:

  • 引用计数算法
  • 可达性分析

引用计数算法

这是一种比较老的回收算法,其原理是每个对象都维护一个引用计数器,当一个对象存在一个引用就增加一个计数,删除一个引用则减少一个计数,垃圾回收时只回收计数器为0的对象。
其缺点是,当两个对象循环引用时无法回收。

可达性分析

通过一系列名为GC Roots的对象作为起始点,从这些节点开始向下搜索,从而引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的(注意一定要是到达GC roots)。

那么那些点可以作为GC Roots呢?

  1. 虚拟机栈(栈桢中的本地变量表)中的引用的对象
  2. 方法区中的类静态属性引用的对象
  3. 方法区中的常量引用的对象
  4. 本地方法栈中JNI(Native方法)的引用的对象

几种垃圾回收的算法

标记清除算法

  1. 从根节点标记被引用的对象。
  2. 将未被标记的对象进行清理。 此方法的缺点是,被清理后的内存空间并不连续,会产生内存碎片,在分配大对象的时候,可能导致无法分配。

复制算法

  1. 吧内存空间分为两个相同大小的独立的区域,每次只使用其中一个。
  2. 垃圾回收时将需要保留的对象复制到另一个内存区域中。
  3. 清除需要回收的内存区域。 此方法的缺点是,会导致内存空间浪费

标记整理算法

  1. 从根节点标记被引用的对象。
  2. 遍历堆,在清除未被标记的对象的同时,将存活的对象顺序存放到堆内存中的一块 此方法解决了内存碎片的问题,也避免了内存空间浪费的问题

分代回收策略

在进行垃圾回收的时候,基于“不同的对象的生命周期是不一样的”这一情况,因此可以对不同的对象进行不同的回收方式。
例如某些对象是长时间存在的:http session、线程等,但某些对象诸如临时变量只是使用一次就可能不再使用;如果使用同一的内存回收方式,则每次都要遍历整个堆进行回收,会降低回收的效率。

如何分代

将堆内存分为三个区:年轻代(Young Generation)、年老代(Old Generation)、持久代(Permanent Generation)。

  • 年轻代
    年轻代又被分为三个区:伊甸取(Eden区)、两个存活区(survivor)。
  1. 新产生的对象都存放于eden区。
  2. 当eden区域满了的时候,将还存活的放入其中一个Survivor01。
  3. 当Survivor01区满了的时候,将其中还存活的对象放入Survivor02。
  4. 当Survivor02满了的时候,将经经历过上一个survivor区的放入年老代,将只经历过一个survivor区域的复制到另一个survivor区。
  • 年老代
    年轻代中可以配置N个survivor区域,当一个对象经历过N个survivor区域后,会被放到年老代中。

  • 持久代
    存放静态文件,如今Java类、方法等,持久代对垃圾回收没有显著影响;如果需要频繁动态调用一些类,例如反射调用的情况下,可以适当调整持久代的内存大小。

垃圾回收的触发

垃圾回收的触发主要是触发Scavenge GC和full GC。

  • Scavenge GC: 当新的对象生成,分配到eden区时,会触发Eden区域的垃圾回收,并且吧尚且存活的对象复制到survivor区域。
  • Full GC:老年代、持久代被写满;system gc被显示调用;full gc会对整个年轻代、年老代、持久代进行整理,故会耗时较长。

JVM优化主要优化fullGC的频率。

垃圾回的方式

垃圾回收器在进行垃圾回收时,一般使用以下三种方式:

  • 串行回收:单核单线程执行,执行过程中挂起用户进程
  • 并行回收:多线程执行,执行过程总挂起用户进程,适用于多核机器,理论上核数越多效率越高
  • 并发回收:不挂起用户线程,回收线程和用户线程同时进行

垃圾回收器

名称使用算法备注
串行收集器Serial复制算法最古老的收集器,单线程收集,用于新生代
并行收集器ParNew复制算法Serial多线程版本,用于新生代
Parallel Seaverage复制算法多线程,更加关注吞吐量,自适应调节策略达到控制吞吐量;用于新生代
Serial Old标记-整理算法单线程,用于年老代
Parallel Old标记-整理算法多线程,用于年老代
CMS标记清除算法并发多线程,老年代收集器
G1复制算法+标记-整理算法目前最先进的回收器,不区分新生代和年老代

参考资料

JVM

转载于:https://my.oschina.net/u/3457546/blog/3095497

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值