最近在看JAVA虚拟机规范,谈下自己对java堆栈的理解
java虚拟机内存分为:栈、本地方法栈、堆、程序计数器、方法区
JAVA栈
java栈中的运行单位是栈帧。
class ActivityThread {
public void main() {
int index = 0;
Student student = new Student();
}
}
上面一段代码很简单,讲下其运行过程:
1:java虚拟机查找方法区中是否已经加载了ActivityThread的字节码信息,如果没有,则加载其字节码并保存到方法区。将静态成员变量保存到方法区的静态存储区(此时会完成静态成员变量的初始化,只有一次初始化);将常量保存到常量池中;多态的动态链接也发生在这一步
2:确定堆区域要调用的main()方法,然后java虚拟机会到方法区中找到main方法的字节码,生成对应的栈帧,压栈运行。
PS:第二步栈帧也是要占内存的,其内存大小在创建栈帧时就已经确定,并且在运行过程中不会发生变化。原因就是栈帧中有一个局部变量表,其中的所有类型并且所占空间在编译时都已经确定。虚拟机将所有数据类型定义为u1类型,long和double定义为u2类型,u1占4个字节,u2占8个字节,都是以u1和u2为单位操作的。
3:index和值0,会被存放到栈帧的局部变量表中。执行Student student = new Student();这一行时,如果方法区没有Student信息,java虚拟机加载Student。student是对象的别名,存放的是new Student()对象在堆中的起始地址
4:方法运行结束,销毁栈帧
5:栈和程序计数器都是线程独立的,即每个线程都有自己的栈和程序计数器
6:栈大小包括指定栈深度和动态申请两种,分别可能发生栈溢出或者OOM
JAVA堆
堆是用来存储对象的。有很多很多种垃圾回收器,前面有篇博客介绍了JAVA对象的创建和回收,这里就不在多说。
对象销毁
一个对象的销毁要经过两次标记,第一次标记:GC ROOT不能到达时会把对象标记为死对象,然后将该对象放入F-Queue列,java虚拟机会创建线程单独处理F-Queue中的对象,此时会调用对象的finalize()方法,在此方法中,可以将该对象复制给其他引用,这样就可以把该对象再次加入引用链。第二次标记:如果在后续的GC过程中,如果GC ROOT再次不能到达此对象,对象会被第二次标记为死对象,然后直接回收掉。
网友评论