【JVM】- 分代、GC算法

一、分代

左图是运行时数据区逻辑图,右图是分代逻辑图,右图中上边部分是JDK1.8之前的,下图是JDK1.8之后的;两张图中相同颜色代表相同的区域。

从图中我们可以得出,新生代和老年代是属于堆的;在JDK1.8之前,方法区也称为老年代,JDK1.8之后,取消了老年代,取而代之的是元空间Meta Space,也即是1.8后,方法区的实现方式有老年代变为了元空间。

设计元空间的目的,一是规避永久代溢出的问题;二是类似ArrarList,可以自动扩容。

1、为什么分代

因为对象的生命周期不一样,有的对象朝生夕死,一次minorGC的时候,大概98%的对象会被回收。但是有的对象生命周期比较长,如果堆内存不分代,所有对象存在相同的区域,那么垃圾回收的时候就会变的很复杂。分代后,垃圾回收就可以按区域的不同,采用不同的回收方式,比如新生代GC回收称为minor GC,老年代的GC回收称是GC,还有Full GC,同时回收新生代和老年代。

2、新生代为什么是8:1:1?

新生代采用的GC方式是复制回收算法,具体方式下边会讲到,这种算法第一次执行minorGC后,还存活的对象会复制到S0区,第二次执行minorGC,eden和S0中还存活的对象会被复制到S1区,如果接下里某次的minorGC后,存活的对象在S1区放不下了,就会存入老年代。

我们的理想的情况是不进入老年代。如果是9:1的话,第一次minorGC后存活的对象复制到S0区,下一次minorGC,存活的对象就会被放入老年代,但我们的理想情况是不进入老年代。所以如果是8:1:1的话,就可以多一份缓冲,占8份的Eden放不下了,触发minor gc,回收后存活的放入s0;eden再次分配,且只能在Eden去分配 ,Eden再次放不下时再次触发minor gc,这次会回收Eden和S0中的内从,存活的放入S1;如果某次回收后S1也放不下,再存入老年代。

以上均是大白话解释,又不准的地方望各位指正。接下来我们看看GC算法。

我们先看看哪些内存需要回收:

程序计数器、虚拟机栈、本地方法栈是每个线程私有的内存空间,随线程而生,随线程而亡。因此这3个须臾的内存分配和回收是确定的,无需考虑内存回收的问题。

但方法区和堆就不同了,一个接口的多个实现类需要的内存可能不一样,我们只有在程序运行期间才会知道创建哪些对象,这部分内存的分配和回收都是动态的,GC主要关注的是这部分内存。总而言之,GC主要进行回收的内存是JVM中的方法区和堆。

二、GC

1、对象创建

在语言层面上,创建对象通常仅仅是一个new关键字而已,而在虚拟机中,一个普通对象的创建是怎样的呢?

虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行响应的类加载过程,在类加载检查通过后,接下来虚拟机将为新生对象分配内存。

2、对象分配

对象分配有两种方式:指针碰撞和空闲列表。

2.1、指针碰撞,适用于内存规整的情况,所有分配的内存都是规整的放到一边,空闲的另一边,中间有指针作为指示器,如果新来的对象,就把指针方空闲区挪动一部分

2.2、空间列表适用于内存不规整的情况,需要空间列表来记录内存使用情况

3、什么样的对象需要回收

什么样的对象需要回收,也就是Java的GC什么时候回收垃圾。有两种判断算法,来判断何时就可以回收了:引用计算法和可达性分析

3.1、引用计算法(废弃)

就是给对象添加一个引用计数器,每当有一个地方引用他时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是可以被回收的。

但是这样方法存在一个问题,就是循环引用给的问题,如果a引用了b,b引用了a,a的计算为1,b的计算也为1,这样他两的计算为1,GC就一直无法回收。同时每次计数器的增加和减少都带来了很多额外的开销,所以在JDK1.1之后,这个算法已经不再使用了。

3.2、可达性分析(使用)

就是通过一系列的称为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到任何一个GC Roots都没有引用链相连时,就证明该对象可以被回收了。

哪些对象可称为GC Roots呢?

是否可以称为GC Roots的关键在于,如果一个线程在运行某个方法,那么这个方法中的变量就是存活状态,就是不应该被回收的,那么这个变量就可以作为GC Roots。

所以可以作为GC Roots的对象有:

  1. 虚拟机栈中本地变量表引用的对象
  2. 方法区中类静态变量引用的对象和常量引用的对象
  3. 本地方法栈中JNI引用的对象

4、java中引用类型有哪些

上边判断什么样的对象需要回收的两种方法,都涉及到引用,Java中对象的引用分为四种级别,这四种级别由高到低依次为:强引用、软引用、弱引用、虚引用。这四种引用均存在于堆中,一个对象属于内中引用,有他的最强的引用决定。

4.1、强引用

我们写代码天天在用的就是强引用、如果一个对象被人拥有强引用,那么垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OouOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。

4.2、软引用 SoftReference

如果一个对象具有软引用,那么如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收期没有回收它,该对象就可以被程序使用。

软引用可用来实现内存敏感的高速缓冲。在jvm报告内存不足之前会清除所有的软引用,这样一来gc就有可能手机软可及的对象,可能解决内存吃紧问题,避免内存溢出。什么时候被收集取决于gc的算法和gc运行时可用内存大小。

4.3、弱引用 WeakReference

如果一个对象只具有弱引用,那该类就是可有可无的对象,因为只要该对象被gc扫描到了随时都会把它干掉。弱引用和软引用给的区别就是:不管当前内存空间是否足够,只要gc扫描到随时会回收。

4.4、虚引用 PlantomReference

虚引用就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么他就和没有任何引用一样,在任何时候都可能被垃圾回收。虚引用主要用来跟踪对象被垃圾回收的活动。

5、回收方法

回收方法有三种:标记-清除算法、复制回收算法、标记-整理算法、还有分代收集算法

5.1、标记-清除算法

先标记要回收的对象,然后统一回收;适用于对象较多的垃圾回收;缺点是标记清除后产生大量不连续的内存碎片,给大对象分配内存时没有足够连续的内存空间,导致提前出发垃圾回收动作。

5.2、复制回收算法

将可用内存划分成相等大小两块,每次只使用其中一块,当这一块用完后将还存活的对象复制到另一块,然后将已使用过的内存一次清理。

适用于存活对象较少的垃圾回收;

优点是每次对整个半区进行内存回收,不用考虑内存碎片问题,只要移动堆顶指针,按顺序分配内存即可;实现简单,运行高效

缺点是将内存缩小了一半;

新生代采用的正是复制回收算法。新生代内存按照8:1:1分为Eden,From Survivor,To Survivor三个空间,每次使用Eden和From Survivor两个空间给对象分配内存,当内存不足垃圾回收时,将存活对象复制到To Survivor空间,然后清理Eden和From Survivor空间;这样相当于内存指浪费了10%;如果10%的To Survivor空间不够存放存活对象时需要老年代进行分配担保(将存活对象通过分配担保机制直接进入老年代)

5.3、标记-整理算法

先标记要回收的对象,将存活对象移至一端,最后清理端边界以外的内存;这样回收后不会产生内存碎片。

5.4、分代收集算法

根据对象存活周期将内存划分为新生代和老年代,然后根据每个年代的特点使用合适的回收算法;如:新生代存活对象少可以采用复制算法; 老年代存活对象多并且没有分配担保必须使用标记清理或标记整理回收算法

6、垃圾回收器

如果两个收集器之间存在连线,就说明他们可以搭配使用。

新生代收集器

6.1、Serial收集器,收集时必须暂停其他所有用户线程,直到收集结束。

6.2、parNew收集器,是Serial收集器的多线程版本

6.3、Parallel Scavenge收集器,主要关注吞吐量的控制,关注时间利用率

吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间) ; 如果虚拟机总共运行100分钟,收集花费1分钟,则吞吐量为99%

老年代收集器

6.4、Serial Old收集器,是Serial收集器的老年代版本的单线程收集器

6.5、Parallel Old收集器,是Parallel Scavenge收集器的老年代版本的多线程收集器

6.6、CMS收集器(Concurrent Mark Sweep),CMS是一款并发收集,低停顿的收集器,关注目标是最短回收停顿时间

6.7、G1收集器,采用标记-整理算法,原理是G1将新生代和老年代分为大小相等的独立区域,进行全区域垃圾回收,新生代和老年代不再是物理隔离,都是部分独立区域的集合;通过计算每个区域垃圾堆积的价值(回收可得到的空间/回收所需要的时间),然后根据价值大小有优先级地进行垃圾回收,保证了回收的效率;

 

----------------------------------有不正确的望各位指正。-----------------------------------------------

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木子松的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值