垃圾回收机制(GC)篇

1.啥叫垃圾回收机制

Java的垃圾回收机制是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间,英文名是GC( Garbage Collection )。
垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存。
在这里插入图片描述

2.哪些内存需要回收?

堆和方法区的内存需要回收,其余的不需要回收。
因为只有堆和方法区是线程共享的,其余的是与线程“同生共死”的,线程结束,内存自然就跟着回收了,所以也就没有垃圾之说了

3. 什么时候回收?

1)在堆里面:
当对象“死了”的时候就要对其进行内存回收了。啥叫对象死了?就是没有地方引用它了,它无用了。

怎么判断一个对象是否还存在着引用?java中的引用分为4种:
强引用: Object o=new Object(),只要强引用存在,GC永远不会回收掉被引用的对象。
软引用: 描述一些还有用但非必需的对象。当系统即将发生内存溢出了,就会对其进行回收。
弱引用: 只要进行GC,就会对其进行回收。
虚引用: 这是最弱的一种引用关系,无法通过虚引用来取得一个对象实例。它的作用是:能在这个对象被收集器回收时收到一个系统通知。
2)在方法区里面:
我们知道,方法区里存储的是已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。所以我们在方法区里面进行垃圾回收,回收的是一些废弃的常量和无用的类。

怎么判断一个常量是否被废弃了?
看引用计数就可以,如果没有对象引用该常量,则说明此常量被废弃了,也就可以回收了。

怎么判断一个类是无用的类?有3种情况:
a、该类所有的实例都已经被回收。
b、加载该类的ClassLoader已经被回收。
c、该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。

4.如何回收?在这里插入图片描述

Java将堆内存分为3大部分:新生代、老生代和永久代。对新生代,主要采用复制算法,而针对老生代,通常采用标记-清除算法或者标记-整理算法来进行回收。

  1. 新生代
      所有新生成的对象首先都是放在Eden区。 年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象,对应的是Minor GC,每次 Minor GC 会清理年轻代的内存,算法采用效率较高的复制算法,频繁的操作,但是会浪费内存空间。当“年轻代”区域存放满对象后,就将对象存放到年老代区域。
  2. 老生代
      在年轻代中经历了N(默认15)次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。年老代对象越来越多,我们就需要启动Major GC和Full GC(全量回收),来一次大扫除,全面清理年轻代区域和年老代区域。
  3. 持久代
      用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响。

复制算法的思想是将内存分成大小相等的两块区域,每次使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另一块区域上,然后对该块进行内存回收。
标记清除顾名思义是一种分两阶段对对象进行垃圾回收的算法。
第一阶段:标记。从根结点出发遍历对象,对访问过的对象打上标记,表示该对象可达。
第二阶段:清除。对那些没有标记的对象进行回收,这样使得不能利用的空间能够重新被利用。
标记-整理(Mark-Compact)算法不直接对可回收对象进行清理,而是让所有可用的对象都向一端移动。然后直接清理掉边界意外的内存。

5.补充

内存溢出: 系统无法再分配出你需要的空间。比如在堆中无法再给新生的对象分配内存了,在栈里栈满了无法再让新栈帧进栈了。
内存泄漏: 内存被无用对象占用着不还,就叫内存泄露。这些对象占用内存但不会被GC所回收。