Java的垃圾回收机制,使java程序员在编写java程序时,不需要像c语言等要不断手动进行垃圾回收,不需要考虑内存管理。这也是java的一大优点,可以说很大程度提高了java程序开发的效率,也大大减少了程序员所需编写的代码量。
java中的垃圾回收是通过“垃圾回收器”来实现的:垃圾回收器作为一种低级别的线程运行(线程优先级非常低),但当内存不足,需要进行垃圾内存清理时,java虚拟机会优先调用垃圾回收器。
垃圾回收器回收什么样的内存?
1.回收java虚拟机中的内存
2.重点关注堆和方法区的内存。因为方法计数器、虚拟机栈、本地方法栈都是线程私有的区域,随线程而生,随线程而灭。栈中的栈帧随着方法的进入和退出而进行着入栈和出栈的操作,每个栈帧中分配多少内存是在类结构确定时就已知的。所以这三个区域中的内存分配和回收都具有确定性。
jvm怎么知道什么样的内存需要被回收?
目前有两种主要的方法:引用计数法和root搜索算法
1.引用计数法:
每个对象都有一个引用计数。每当该对象被引用一次时,引用计数就会+1,对象引用被释放,引用计数-1。当引用计数为0时,对象标识可以回收。
但这种引用有一定的缺陷。例如循环引用的情况下,循环引用的对象不会被回收。
2.root搜索算法:
jvm定义了几个root对象,这几个对象不会被回收。所以这些对象所引用的对象都是正在使用的对象,这些对象未使用的对象就是即将要被回收的对象。也就是说,如果一个对象能够到达root,那么这个对象就不会被回收;反之,如果一个对象不能够到达root,那么这个对象就会被回收。
以下对象会被认为是root对象:
被启动类(bootstrap加载器)加载的类和创建的对象
jvm运行时方法区类静态变量(static)引用的对象
jvm运行时方法去常量池引用的对象
jvm当前运行线程中的虚拟机栈变量表引用的对象
本地方法栈中(jni)引用的对象
由于这种算法即使存在互相引用的对象,但如果这两个对象无法访问到根对象,还是会被回收。例如:对象C和对象D互相引用,但是由于无法访问根,所以会被回收。
jvm在确定是否回收的对象的时候采用的是root搜索算法来实现。
System.gc()
垃圾回收器在不可预知的情况下对内存中已经死亡或者长时间没有使用的对象进行清除和回收。程序员不能实时的调用垃圾回收器对某个对象或者所有对象进行回收。
可以手动执行System.gc();
,通过GC运行(只是请求建议,并不一定真正运行)。
//main方法
public class Demo_1 {
public static void main(String[] args) {
Test t1 = new Test();
Test t2 = new Test();
Test t3 = new Test();
t1 = null;
t2 = null;
t3 = null;
//System.gc();
}
}
//定义一个测试类,重写了父类Object中的finalized方法
//finalized方法在对象释放前会自动调用
class Test{
public void finalize() {
System.out.println("我即将被释放!");
}
}
运行结果: