虚拟机学习总结-内存区域
虚拟机的内存区域划分
JAVA虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域
1.程序计数器
当前线程所执行的字节码的行号指示器,字节码解释器就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。每条线程都需要有一个独立的程序计算器(线程私有)。如果线程正在执行的是一个java方法,计数器记录的就是正在执行的虚拟机字节码指令地址,如果执行的是native方法,计数器值为空4
2.虚拟机栈
每个方法在开始执行时都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息,调用开始就是栈帧入栈,执行完毕就是栈帧出栈。
Long 和double占用两个局部变量空间,其余的占用一个。局部变量表所需要的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,在运行期间不会改变局部变量表的大小。
StackOverflowError: 线程请求的栈深度大于虚拟机所允许的深度。
OutOfMemoryetror: 虚拟机栈无法申请足够的内存。
3.本地方法栈
为native方法服务,虚拟机栈为java方法服务,
4.方法区
各个线程共享,存储已被虚拟机加载的类信息,常量,静态变量,即时编译后的代码等数据。还包括运行时常量池:运行期间也可以将常量放入常量池。
5.堆
存放对象实例,几乎所有的对象实例都在这里分配内存。是垃圾收集器管理的主要区域。可分为新生代和老年代。
对象的创建
1.确保类信息已经加载
遇到 new 指令时,首先去检查这个指令参数是否能够在常量池中定位到一个类的符号引用,并且保证这个符号引用代表的类已被加载初始化。
2.分配内存
在类加载检查通过后,对象所需内存大小便已经确定。接下来虚拟机将为新生对象分配内存。指针碰撞和空闲列表分配法。将分配到的内存空间初始化为零值(除对象头)。
3.进行必要的一些设置
对对象进行必要的设置,如那个类的实例,哈希码,GC 分代年龄等信息。
4.执行init()方法
在此之前,这个对象的所有字段都只是初值,这个步骤就是按照程序员的意愿进行初始化。
对象的内存布局
包括对象头(包括运行时数据和类型指针),实例数据,对齐填充(保证对象的大小正好是八字节的整数倍)。,
对象的访问定位。
通过句柄访问对象
好处是reference中存储的是稳定的句柄地址,在对象被移动时只会改变实例数据指针,reference 本身不会修改干
通过直接指针访问对象
好处就是速度更快,它节省了一次指针定位的时间开铜
String.intern()
这是一个Native方法,如果字符串常量池中已经包含一个等于次String对象的字
符串,则返回代表池中这个字符串的String对象爱你乖,否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。