JVM学习-基础篇-垃圾回收

张开发
2026/4/16 13:15:48 15 分钟阅读

分享文章

JVM学习-基础篇-垃圾回收
垃圾回收在C/C这类没有自动垃圾回收机制的语言中一个对象如果不再使用需要手动释放否则就会出现内存泄漏。内存泄漏指的是不再使用的对象在系统中未回收内存泄漏的积累可能会导致内存溢出。Java中为了简化对象的释放引入了自动的垃圾回收Garbage Collection简称GC机制。通过垃圾回收器来堆不再使用的对象完成自动的回收垃圾回收器主要负责对堆上内存进行回收。垃圾回收器如果发现某个对象不再使用就可以回收该对象。自动垃圾回收自动根据对象是否使用由虚拟机来回收对象优点降低程序员实现难度降低对象回收bug 的可能性缺点程序员无法控制内存回收的及时性手动垃圾回收由程序员编程实现对象的删除优点回收及时性高由程序员把控回收的时机缺点编写不当容易出现悬空指针、重复释放、内存泄漏等问题首先线程不共享的部分都是伴随着线程的创建而创建线程的销毁而销毁。而方法的栈帧在执行完方法之后就会自动弹出栈并释放掉对应的内存。所以这一部分不需要垃圾回收器负责。方法区的回收方法区中能回收的内容主要就是不再使用的类。判定一个类可以被卸载。需要同时满足下面三个条件1、此类所有实例对象都已经被回收在堆中不存在任何该类的实例对象以及子类对象。2、加载该类的类加载器已经被回收。3、该类对应的 java.lang.Class 对象没有在任何地方被引用。如何判断对象可以回收垃圾回收器要回收对象的第一步就是判断哪些对象可以回收。Java中的对象是否能被回收是根据对象是否被引用来决定的。如果对象被引用了说明该对象还在使用不允许被回收。第一行代码执行之后堆上创建了Demo类的实例对象同时栈上保存局部变量引用堆上的对象。第二行代码执行之后局部变量对堆上的对象引用去掉那么堆上的对象就可以被回收了。一个更复杂的案例这个案例中如果要让对象a和b回收必须将局部变量到堆上的引用去除。那么问题来了A和B互相之间的引用需要去除吗答案是不需要因为局部变量都没引用这两个对象了在代码中已经无法访问这两个对象即便他们之间互相有引用关系也不影响对象的回收。判断对象是否可以回收主要有两种方式引用计数法和可达性分析法。引用计数法引用计数法会为每个对象维护一个引用计数器当对象被引用时加1取消引用时减1。比如下图中对象 A 的计数器初始化为0局部变量 a1 对它引用之后计数器加 1 就变成了 1。同样 A 对 B 产生了引用B的计数器也是1。引用计数器的优点是实现简单缺点主要有两点每次引用和取消引用都需要维护计数器对系统性能会有一定的影响。存在循环引用问题所谓循环引用就是当A引用BB同时引用A 时会出现对象无法回收的问题。下图由于A 和 B之间存在互相引用所以计数器都为1两个对象都不能被回收。但是由于没有局部变量对这两个代码产生引用代码中已经无法访问到这两个对象理应可以被回收。可达性分析法Java使用的是可达性分析算法来判断对象是否可以被回收。可达性分析将对象分为两类垃圾回收的根对象GC Root和普通对象对象与对象之间存在引用关系。下图中A到B再到C和D形成了一个引用链可达性分析算法指的是如果从某个到 GC Root 对象是可达的对象就不可被回收。哪些对象被称之为GC Root对象呢线程Thread对象引用线程栈帧中的方法参数、局部变量等。系统类加载器加载的java.lang.Class对象引用类中的静态变量。监视器对象用来保存同步锁synchronized关键字持有的对象。本地方法调用时使用的全局对象。

更多文章