垃圾是指:在程序运行中没有任何指针指向的对象,这个对象就是要被回收的垃圾,如果不进行垃圾回收,那么可能会出现内存溢出等异常
没有 GC 就不能保证应用程序的正常运行
JVM 使用自动内存管理,减低了内存泄漏以及内存溢出的风险,让程序员可以专注于业务开发。
在 GC 回收垃圾之前,需要区分出内存中哪些是存活对象,哪些是已死亡的对象,只有已经死亡的对象,才会执行垃圾回收,释放占用的内存空间,因此这个过程叫垃圾标记阶段
方式一:引用计数算法:
对于每个对象保存一个整型的引用计数器属性,用于记录对象被引用的情况
举例:对于一个对象 A,只要有任何一个对象引用了 A,则 A 的引用计数器就加一,引用失效的时候减一,只要对象 A 的引用计数器为 0,则表示不能被使用,进行回收即可
优点:实现简单,垃圾对象便于辨识,回收没有延迟
缺点:无法处理循环引用的情况,如下图,对象没有价值,但是回收不掉
所以 java 并不适用引用计数算法,但是 python 使用,手动解除
方式二:可达性分析算法(根搜索算法,跟踪性垃圾收集):
能够解决在引用计数算法中循环引用的问题,防止内存泄露的发生
基本思路:
1、是以根对象集合为起始点,按照从上到下的方式 搜索被本对象集合所连接的目标对象是否可达
2、使用可达性分析算法后,内存中存活对象都会被根对象集合直接或者间接连接,搜索所走过的路径成为引用链
3、如果对象没有任何引用链相连接,则不可达,说明死亡,可以回收
4、只有能够被根对象集合直接或者间接连接的对象才是存活对象
举例:一串葡萄,如果都相连,说明都是存活对象,但是如果有的葡萄掉了,说明是死亡对象,需要被垃圾回收
在 java 语言中,GCRoots可以是哪些元素呢
1、虚拟机栈当中的引用对象
2、本地方法栈中 JNT 引用的对象
3、方法去中类静态属性引用的对象
4、方法去中常量引用的对象
5、所有被同步锁 synchronized 持有的对象
6、java 虚拟机内部的引用
finalization 机制:
Java 语言提供了对象终止机制来允许开发人员提供对象被销毁之前的自定义处理逻辑,finalize() 方法允许在子类中被重写,用于在对象被回收时进行资源释放
不要主动地去调用 finalize() 方法,应该交给垃圾回收机制进行调用,原因:
1、在使用 finalize() 时可能会导致对象复活
2、方法的执行时间是没有保障的,完全由 GC 线程决定,极端情况下,若不发生GC,则 finalize 方法将会没有执行机会
3、一个糟糕的 finalize 方法会严重影响 GC 的性能
由于 finalize() 方法的存在,虚拟机对象一般处于三种可能的状态
1、可触及的
2、可复活的
3、不可触及的(不可触及的对象不可能被复活,因为 finalize() 只会被调用一次)
判断一个对象是否可回收,需要经历两次标记过程
1、如果对象 obj 到 GCRoots 没有引用链,则进行一次标记
2、判断是否有必要执行 finalize()方法:
如果对象 没有重写 finalize() 方法,或者已经被虚拟机调用过,则会被虚拟机视作没有必要执行,objA 被判定为不可触及的。
如果对象重写了finalize 方法,而且没有被执行,则会执行
finalize() 方法是对象脱离死亡的最后机会,如果在方法已经被调用过,那么不会再次调用(finalize() 方法只会被调用一次)