一、JVM内存模型
1、栈(线程私有)
栈又称方法栈,线程私有的,线程执行方法是都会创建一个栈阵,用来存储局部变量表、操作栈、动态链接、方法出口等信息。调用方法时执行入栈,方法返回式执行出栈在方法中声明的变量可以是基本类型的变量,也可以是引用类型的变量。
1、当声明是基本类型的变量的时,其变量名及值(变量名及值是两个概念)是放在JAVA虚拟机栈中(栈帧中)
2、当声明的是引用变量时,比如String s=new String(“aaaa”),所声明的变量s(该变量实际上是在方法中存储的是内存地址值)是放在JAVA虚拟机的栈中,该变量所指向的对象“aaaa”是放在堆内存中的
2、本地方法区(线程私有)
与栈类似,也是用来保存执行方法的信息。执行Java方法是使用栈,执行Native方法时使用本地方法栈。
3、程序计数器(线程私有)
保存着当前线程执行的字节码位置,每个线程工作时都有独立的计数器,只为执行Java方法服务,执行Native方法时,程序计数器为空。
4、堆(线程共享)
JVM内存管理最大的一块,对被线程共享,目的是存放对象的实例,几乎所欲的对象实例都会放在这里,当堆没有可用空间时,会抛出OOM异常。根据对象的存活周期不同,JVM把对象进行分代管理,由垃圾回收器进行垃圾的回收管理。
5、方法区(线程共享)
方法区又称非堆区,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器优化后的代码等数据。1.7的永久代和1.8的元空间都是方法区的一种实现。
在类中声明的变量是成员变量,也叫全局变量.
那成员变量又是存在于哪里呢,网上有的说是在堆里,有的说在方法区里.
其实严格来说,两者都有存在,方法区里存有类信息,常量,静态变量,编译后的class文件等,既然是类信息,那么一个class类中的方法名,类名,成员变量名称等都属于该类的信息,也是存在于方法区中,也就是一个类中的成员变量名称是存在于方法区中的,但是在我们new一个对象后,这个对象上包含的成员变量的值是放入堆中的。
二、GCRoot作用
以GC Roots为根节点,根据引用关系向下搜索,搜索过程走过的路径称为引用链,如果某个对象到GC Roots之间没有引用链相连,那这个对象就是可回收的垃圾对象。
1、为什么需要GCRoot
我们知道Java堆里面有未被引用的、已被引用的两类对象,问题是我们有什么依据判断谁是垃圾对象需要被回收?换句话说,我们如何判断一个对象被引用?这就需要我们从一个点出发找出他所有的引用对象。这个点就是GCRoot。
2、谁能担任GCRoot
GCRoot的作用就是从这点出发,找到所有的可到达的引用对象,且这个对象必须不能是待回收的对象。我们知道JVM结构有 栈、方法区、本地方法区、程序计数器、堆这几种结构,其中栈、方法区、本地方法区、程序计数器是线程私有的,这几个区的数据随着线程的创建而创建,线程的回收而消失,所以这几个区适合做GCRoot。从这几个部分出发就可以找到非垃圾对象。具体做GCroot由以下几类,他们的共同特点就是线程私有。
- 虚拟机栈(javaStack)(栈帧中的局部变量区,也叫做局部变量表)中引用的对象
- 方法区 类静态属性引用的对象
- 方法区 常量引用的对象
- 本地方法区 JNI(Native方法)引用的对象
三、GCRoot遍历算法
xxxx 待更新
四、Stop the World原因
JVM中对象引用是浮动的,只有暂停所有的客户线程,才能做好标记。然后根据标记的对象做后续处理,STW其实就类似一个快照。