Java垃圾回收机制(GC)

什么是垃圾(堆):

1、没有被引用的对象就是垃圾对象

2、所有不再存活的对象

3、没有对象引用指向原先分配给某个对象的内存时(百度百科)

Java栈空间垃圾回收:

1、我们定义一些基本类型的变量和对应的变量数据还有对象的引用变量,都在函数的栈内存中分配。当在一段代码块定义一个局部变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,该变量就称为垃圾,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。 

Java堆空间垃圾回收:

Java语言规范没有明确地说明JVM使用哪种垃圾回收算法,但任何一种垃圾收集算法一般要做2件基本的事情:(1)发现垃圾;(2)回收垃圾占用的内存空间,使该空间可被程序再次使用。

判断垃圾的常见算法:

1、引用计数法(Reference Counting Collector):

没有被引用的对象就是垃圾对象。那么我们为每一个创建的对象都分配一个引用计数器。当对象被引用时,计数器就+1 当引用计数器为0时,就意味着该对象没有被引用,那么该对象就是垃圾对象。但该方案有个问题,就是无法检测“循环引用”:当两个对象互相引用,它俩的计数都不为零,即使它们对象本身都不被外界任何东西引用(垃圾),但引用计数器却不为0,所以占用的内存空间永远不会被回收。

2、可达性分析法(tracing算法、标记和清除(mark-and-sweep)垃圾收集器):

tracing算法是为了解决引用计数法的问题而提出的。基本思路是把所有引用的对象想象成一棵树,从树的根结点(根集) GC Roots 出发,持续遍历找出所有连接的树枝对象,这些对象则被称为“可达”对象,或称“存活”对象。其余的对象则被视为“死亡”的“不可达”对象,或称“垃圾”。

那么什么对象可以是GC Roots?

GC Roots 本身一定是可达的,这样从它们出发遍历到的对象才能保证一定可达。那么,Java 里有哪些对象是一定可达呢?

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

2.2、方法区中静态属性引用的对象

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

2.4、本地方法栈JNI引用的对象

GC Roots涉及到 JVM 本身的内存结构,先简单知道有这么几种类型的 GC Roots 每次垃圾回收器会从这些根结点开始遍历寻找所有可达节点。

垃圾的回收方式:

红色:垃圾对象  蓝色:存活对象 绿色:空白内存空间 

1、标记-清理:(tracing算法)

第一步,标记:利用可达性遍历堆内存,把“存活”对象和“垃圾”对象进行标记

第二步,清理:把所有“垃圾”对象所占的空间直接清空

 

该方式简单方便 ,但是容易产生内存碎片。

2、标记-整理(compacting算法(Compacting Collector))

相同第一步,标记:利用可达性遍历堆内存,把“存活”对象和“垃圾”对象进行标记

第二步,整理:清理垃圾对象时,把存活的对象整理到同一个地方

3、复制(copying算法) 

把堆内存分成两部分,一段时间内只允许在其中一部分内存上进行分配,当这块内存被分配完后,则执行垃圾回收,把所有存活 对象全部复制到另一部分内存上,当前部分则直接全部清空。

清理前: 

清理后: 

 

只使用上面部分的内存,直到内存使用完毕,进行垃圾回收,把所有存活对象搬到下半部分,并把上半部分全部清空。该做法不容易产生碎片(会产生碎片),同时它意味着你在一段时间内只能使用一部分的内存,超过这部分内存的话就意味着堆内存里频繁的 复制清空。这种方案适合 存活对象少,垃圾多的情况,这样在复制时就不需要复制多少对象过去(复制对象也消耗资源),多数垃圾直接被清空处理。

猜你喜欢

转载自blog.csdn.net/qq360694660/article/details/83656828