GC介绍之引用计数法

一:JVM垃圾回收机制

     为什么栈不会有垃圾回收机制:栈内存中方法运行完毕后会有弹栈的操作,不会产生垃圾;

     堆内存中却没有这种操作,当堆内存中很多无用的成员变量、对象等等积压到一定程度时,就会发生堆内存溢出的一个错误OutOfMemoryError (Java heap space)堆内存溢出 ,虽然说堆内存的大小是可以调节的,但是它还是解决不了根本问题。那么为了避免这种情况的发生,出现了垃圾回收机制,也就是我们所说的GC。


二:垃圾回收的伊甸区

3.伊甸区(Eden)
      新对象被创建时,通常便会被分配到伊甸区。由于通常都会有多个线程在同时分配大量的对象,因为伊甸区又被进一步划分成一个或多个线程本地分配缓冲(Thread Local Allocation Buffer,简称TLAB)。有了这些缓冲区使得JVM中大多数对象的分配都可以在各个线程自己对应的TLAB中完成,从而避免了线程间昂贵的同步开销。
TLAB中无法完成分配(通常是由于没有足够的空间),便会到伊甸区的共享空间中进行分配。如果这里还是没有足够的空间,则会触发一次新生代垃圾回收的过程来释放空间。如果垃圾回收后伊甸区还是没有足够的空间,那么这个对象便会到老生代中去分配。

三:堆内存的结构

堆内存逻辑上是分为三个部分:新生代、养老代、永久代(jdk1.7以后我们称永久代为元空间)。
在这里插入图片描述
但是实际上负责存储的只有:新生代、养老代。
在这里插入图片描述

四:垃圾回收机制

      回收机制介绍(一种轻GC是在伊甸区和幸存区,一种重GC是在养老区)  注意:没有元空间的垃圾回收机制
对象在伊甸区(Eden)被new出来,当伊甸区满了以后还需要创建对象,这时候JVM会对伊甸区进行垃圾回收(YGC也叫轻GC),将伊甸区中的没有被其他对象所引用的对象进行销毁(finalize()方法用于销毁对象的)。然后将伊甸区中存活的对象移动到幸存0区,并且该对象年龄为1,当伊甸区再满了之后会对伊甸区和幸存0区的对象进行GC,然后会将伊甸区和幸存0区存活的对象移动到幸存1区,如果当前存活的对象GC前是幸存区的,那么他们的年龄+1,就这样GC一次交换一次年龄增长一次,如果有对象经过了15次GC依然存活(15岁),会被转移到养老区(Old),当养老区满了之后也会进行垃圾回收(Full GC也叫重GC),对养老区进行垃圾清理,当最后没有可清理的垃圾时且新生代、养老代都满了之后,会报一个异常:OutOfMemoryError (Java heap space)

     异常原因:
代码中创建了大量的对象,且长时间不能被回收,导致创建新对象出现堆内存溢出。

五:关于新生代GC之后有交换,谁空谁是To的图解:

在这里插入图片描述
文字解释:第一次GC会把存活的对象存入幸存0区(当前的Form区),第二次GC会把所有存活的对象存入幸存1区(当前From区),第三次GC会把所有存活的对象存入幸存0区(当前From区),你会发现每次有对象的哪个区就是From区,没有对象的那个区就是To区。


这样就验证了上面那句:GC之后有交换,谁空谁是To

六:GC的算法有哪些?

标记清除法,标记整理法,复制算法,引用计数法

1.引用计数法(已经不用了)
缺点:老算法,比较消耗内存,比较难处理循环引用。因为运用了计数器,每次都要计数所以比较消耗。

假设A对象用了一次就给它一个计数器为1,假设对象B用了俩次给它计数器为2,假设对象C一次也没有用它的计数器为0,那么对象C就会被垃圾回收进行清除。

2.复制回收算法:(GC 90%用的都是这个,这个算法一般用在我们的新生代)
优点:不会产生内存碎片,效率高。
缺点:浪费内存空间。
最经典的体现在这句话:GC之后有交换,谁空谁是To。 里面所提到的交换其实就是在一次GC之后,把剩余存活的对象复制到下一个幸存区,从而就导致了必须要有两个幸存区的概念 (幸存0区和幸存1区) 所以就是比较消耗内存空间。因为是直接复制的所以比较省时,不会产生内存碎片
一般是将from区的复制到to区,此时谁空谁就定义为to区。(实质就是将我们的幸存区0复制到幸存区1使我们的一个幸存区为空to区永远为空)

当一个对象经历了15次GC就会放入到养老代。底下就是我们的过程图:

 

 3.标记清除算法

扫描这些对象,对活着的对象进行标记,清除的时候将没有标记的进行清除。

优点:不需要额外的空间

缺点:俩次扫描,严重浪费时间,会产生内存碎片。

 

 

4.标记压缩算法

先进行标记那些活着的对象,然后进行清除,清除以后进行整理将活着的对象整理在一起

 

 六:总结

内存效率:复制算法>标记清除算法>标记压缩算法 (时间复杂度)

内存整齐度:复制算法=标记压缩算法>标记清除算法

内存利用率:标记压缩算法=复制算法>标记清除算法

思考问题:有没有最优算法?

没有, 没有最好的算法。  只有最合适的算法---->  GC:分代收集算法

年轻代: 存活率低  复制算法

老年代:区域大:存活率高  标记清除(内存碎片不是太多)+标记压缩混合实现

 

posted @ 2021-03-30 14:32  iLisa  阅读(854)  评论(0编辑  收藏  举报