上篇说到Handler的内存泄露,其实是因为主线程作为GC Root间接引用到了Handler。今天就来简单介绍下JVM中的GC,垃圾回收。
GC,全程Garbage Collection
,垃圾回收。
垃圾,就是内存中没有用的对象。
在Java中,我们无需手动释放内存,在JVM中有垃圾回收器自动帮我们回收。
JVM中通过可达性分析算法来决定对象是否可以回收。
具体做法就是把内存中所有对象之间的引用关系看做一条关系链,
比如A持有B的引用,B持有C的引用。而在JVM中有一组对象作为GC Root,也就是根节点,然后从这些节点开始往下搜索,查看引用链,最后判断对象的引用链是否可达来决定对象是否可以被回收。
为了方便大家理解,我画了一张图来说明:
很明显,ABCD四个引用都是GCRoot
可达的,通俗点讲,就是跟GCRoot直接或间接有关系,有线连着的。而EF虽然直接连着线,但是他们和GCRoot是没关系的,也就是GCRoot
不可达的对象组。
所以当GC发生的时候,EF就会被回收。
在说GC发生的内存区域之前,我们先聊聊JVM中的内存分配。
在JVM中,主要有内存分成了五个数据区域:
程序计数器
:线程私有,主要用作记录当前线程执行的位置。虚拟机栈
:线程私有,描述Java方法执行的内存模型。本地方法栈
:线程私有,描述本地(native)方法执行的内存模型。堆
:存放对象实例。方法区
:存放类信息、常量、静态变量等通过上面的介绍,我们了解到前三个都是线程私有,所以会随着线程的死亡而消失。
而后面两块内存区域,也就是堆和方法区是所有线程共有的,如果不处理可能内存就会一直增长,直到超出可用内存。所以需要借助GC机制对这些区域内的无用内存进行回收,特别是堆区的内存,因为堆区就是存储对象实例的。
那具体什么时候会被回收呢?主要有两种情况:
剩余空间不足
导致对象内存分配失败,这时系统会触发一次 GC。System.gc()
来请求一次 GC。刚才说过了可达性分析算法,所以大家应该知道GCRoot的重要性了。
GCRoot
,说白了就是JVM认证的可以作为老大的人选,只有这些对象是可以作为引用链的头头,掌管并保护着有用的引用。
在Java中,有以下几种对象可以被作为GCRoot
,这些对象是不会被GC的:
这里又涉及到一个问题了,什么是局部变量表。
刚才说过虚拟机栈
是用于支持方法调用或者执行的数据结构,具体是怎么操作的呢?
当某个方法被执行,就会在虚拟机栈中创建一个栈帧
,也就是一个方法就对应着一个栈帧,栈帧会管理方法调用和执行所有的数据结构。
而栈帧中又分为几块存储空间,进行存储方法对应的不同的数据结构,比如局部变量表
就是用于存储方法参数和方法内创建的局部变量。
所以这第一个GC Root
指得就是方法的参数或者方法中创建的参数。
public class GCTest {
public static void test1(){
//局部变量作为GCRoot
GCRoot root=new GCRoot();
System.gc();
}
}
顺便说下栈帧中其他几个内存结构:
局部变量表
:存储方法参数和方法内创建的局部变量操作数栈
:后入先出栈。当方法执行过程中,就会通过操作数栈来进行参数传递,又或者进行加数动态连接
:支持方法调用过程中的动态连接。返回地址
:在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态,而这个返回地址区域就是用于存储返回地址信息的。一般方法正常退出时,是可以将调用者的PC计数器值作为返回地址。这个很好理解,指得就是静态变量。
public class GCTest {
private static GCRoot root2;
public static void main(String[] args) {
//静态变量作为GCRoot
root2=new GCRoot();
System.gc();
}
}
活着的线程,比如主线程,上一篇文章就说过Handler内存泄露的原因就是被主线程所引用,所以无法被回收。
Thread root3=new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
public void test2(){
//活着的线程作为GCRoot
root3.start();
System.gc();
}
在JNI中有如下三种引用类型可供使用:
其中局部引用和全局引用都可以作为GC Root
,不会被GC回收。
周末愉快~
https://kaiwu.lagou.com/course/courseInfo.htm?courseId=67#/detail/pc?id=1856
感谢大家的阅读,有一起学习的小伙伴可以关注下公众号—
码上积木
❤️ 每日一个知识点,建立完整体系架构。