JVM垃圾收集与内存分配策略

来源:互联网 发布:unity3d 获取鼠标位置 编辑:程序博客网 时间:2024/06/03 15:59

Java语言的发展伴随着GC收集器的不断改进,在开发过程中根本不用编写与回收相关的代码,这一切都归功于垃圾收集器。下面从以下三个问题来认识与GC相关的工作。

1、哪些内存需要回收?

2、什么时候回收?

3、如何回收?

一、哪些内存需要回收

通过一系列称为“GC Roots”的对象作为起点,从这些节点开始向下搜索,当一个对象没有和任何引用链相连时,则说明该对象不可用。


可作为GC Roots对象包括下面几种:

1、虚拟机栈(栈帧中的本地变量表)引用的对象。

2、方法去中类静态属性引用的对象。

3、本地方法栈中(一般说的Native方法)引用的对象。

4、方法区中常量引用的对象。

引用类型:

1、强引用:在程序代码中普遍存在的,类似“Object obj = new Object()”这类的引用,只要强引用还存在,垃圾收集器不会回收被引用的对象。

2、软引用:用来描述一些有用但非必须对象。对于软引用关联着的对象,垃圾收集器运行时可能会(可能不会)回收软引用对象。对象是否被回收取决于垃圾收集器的算法以及垃圾收集器运行时可用的内存数量。JDK1.2之后提供了SoftReference类来实现软引用。

3、弱引用:用来描述非必须对象。被弱引用关联着的对象只能生存到下一次垃圾回收发生之前。JDK1.2之后提供了WeakReference类来实现软引用。

4、虚引用:最弱的引用关系。对象的虚引用完全不会对其生命周期构成影响,也无法通过虚引用来取得一个对象的实例。JDK1.2之后提供了PhantomReference类来实现软引用。

二、什么时候回收

        当前商业虚拟机采用分代思想管理内存,根据不同代采用不同的分配策略和垃圾回收算法。不同代垃圾回收触发机制可能也会不一样。新生代采用复制策略,当需要分配的内存不足时就触发新生代GC(Minor GC)。老年代会根据系统设置的空间使用比例参数来触发老年代GC(Major GC)。

三、如何回收

枚举根节点

        垃圾收集器回收的是到GC Roots的引用链不可达对象,在可达性分析时必须在确保一致性的快照中进行。不可以出现在分析过程中对象的引用还在不断变化的情况。这就会导致在GC运行时必须停顿所有Java执行线程(Stop the world)。所以在枚举根节点操作中必须要停顿的。

安全点

        在触发GC回收时让线程在哪里停下来?如何让线程停下来?程序执行时并非在任何地方都可以停顿下来开始GC,只有在到达安全点是才能停顿。安全点的选定基本上是以程序“是否让程序具有长时间执行的特征”为标准进行选定。例如方法调用、循环跳转、异常跳转等。

        在GC发生时,可以通过两种选择让线程跑到安全点停顿下来:抢先式中断和主动式中断。抢先式中断先把所有线程全部中断,发现中断的地方不在安全点上,就恢复线程,让它继续运行到安全点上。主动式中断设置一个标志位,线程执行时让线程主动轮询这个标志位,发现中断标志位为真是就中断挂起。

安全区域

       通过上面分析知道GC发生时执行线程会在安全点上中断,如果线程不执行(处于sleep或block状态),无法响应JVM中断请求,运行到安全点上中断挂起。对于这种情况就需要安全区域来解决。

         安全区域指的是一段代码片段中,引用关系不会发生变化。在这个区域中的任何地方开始GC都是安全的。线程执行到安全区域中的代码时,标识自己已经入安全区域,当GC发生时,就不需要处理这些线程。当线程要离开安全区域时,首先要检查系统是否完成了根节点的枚举,如果完成,线程就继续执行,否则必须等到收到可以离开安全区域信号为止。

回收算法

1、标记-清除算法

标记所有需要回收的对象,标记完成后统一回收被标记的对象。

2、标记-整理算法

标记所有需要回收的对象,让所有存活的对象都向一端移动,然后清理掉端边界以外的数据。

3、复制算法

将内存划分为大小相等的两块,每次只是用一块,当这一块内存用完时,就将还存活的对象复制到另一块内存上,然后再把已使用过的内存空间清理掉。将内存划分为一块较大的Eden区和两块较小的Survivor区(8:1:1),使用Eden和其中一块Survivor存放新对象,发生内存回收时把Eden和Survivor存活的对象复制到另一块Survivor空间上。如果出现存活对象大小大于Survivor空间大小的极端情况时,使用空间分配担保来把不能容纳的对象存放到Tenured空间。

4、分代收集算法

根据对象存活周期不同将内存划分为几块,再根据各个代的特点采用最适当的收集算法。

四、对象如何分配内存空间

1、对象优先在Eden分配:在大多数情况下,对象在新生代Eden区中分配空间,当Eden没有足够的内存空间可用时,虚拟机将发起一次Minor GC。

2、大对象直接进入老年代:需要大量连续内存空间的Java对象为了避免在Eden区以及两个Survivor区之间发生大量的内存复制,令大于系统设置值的对象直接在老年代分配空间。

3、长期存活的对象将进入老年代:虚拟机采用分代的思想来管理内存,那么分配内存时必须能识别哪些对象应放在新生代,哪些对象应放在老年代中。为了做到这一点,虚拟机给每个对象定义了一个对象年龄(Age)计数器。当对象年龄增长到系统设置进入老年代年龄时,就将会晋升到老年代中。如果在Survivor空间的相同年龄段所有对象大小大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,不需要等到对象的年龄大于系统设置值。当老年代没有足够的内存空间可用时,虚拟机将发起一次Major GC。

4、空间分配担保:新生代使用复制回收算法,把存活的对象复制到一个Survivor空间上,如果存活的对象空间大于Survivor可容纳的对象,就需要老年代进行担保,把Survivor无法容纳的对象存放到老年代上。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 淘宝密码忘了怎么办呢 融e借逾期一天怎么办 拼多多处罚下架怎么办 永久无法解绑支付宝怎么办 淘宝下单购买人数太多怎么办 新浪微博被拉黑暂时无法评论怎么办 闲鱼交易成功后卖家反悔怎么办 闲鱼买家不申请介入怎么办 支付宝安装不上怎么办 无线摄像机离wifi太远怎么办 安卓系统死机了怎么办 安卓手机开不了机怎么办 手机关机键坏了怎么办 华为手机接听电话声音小怎么办 小米6x游戏闪退怎么办 安卓8.0不兼容怎么办 安卓8.0应用闪退怎么办 安卓8.0不兼容的怎么办 游戏全屏只有一个分辨率选项怎么办 安卓6.0吃运行内存怎么办 小米手机王者荣耀录像不支持怎么办 win764位系统不兼容怎么办 安卓版本太高不兼容怎么办 安卓3.2.0不兼容怎么办 手机卡和手机不兼容怎么办 vivo手机下载吃鸡不兼容怎么办 vivox3t不兼容支付宝怎么办 移动sim卡坏了怎么办 cpu和主板不兼容怎么办 主板与cpu不兼容怎么办 cpu跟主板不兼容怎么办 软件与电脑不兼容怎么办 win8系统无限重启怎么办 安装微信旧版本登录提示升级怎么办 手机软件与系统不兼容怎么办 下载旧版本微信闪退登陆不了怎么办 企业微信一直登录失败怎么办 360浏览器9.1经常卡死怎么办 手机版爱奇艺看电影屏幕变小怎么办 找不到旧版本米聊怎么办 苹果id被锁了怎么办