一、Java运行时数据区的组成
Java的运行时数据区分为两个区域,一个是线程私有的区域,一个是线程共享的区域。
- 线程私有
- Java虚拟机栈
- 本地方法栈
- 程序计数器
- 线程共享
- 堆
- 方法区
二、Java运行时数据区分析
从上面已经知道了,Java虚拟机运行时数据区按照线程私有与否可以进行划分,线程私有的会随着线程的创建以及销毁,因此这是不需要进行垃圾回收的区域。而线程共享的会进行垃圾回收。
程序计数器
在Java中,假如单核CPU,同时有多条线程跑的情况下,线程之间可能在让出CPU执行权的时候,某条线程的还没执行完被切出去了,那么需要有一个记录此时线程执行的属性的,而完成这一使命的就是程序计数器。
程序计数器用于记录线程执行的字节码的行数,线程的分支跳转、循环、条件控制都基于程序计数器而完成的。
如果线程执行的是Java方法,程序计数器记录的是执行的字节码的指令地址。而如果执行的是Native方法,则这个计数器为空。
Java虚拟机栈
Java虚拟机栈是线程私有的,每个线程都有一个栈,线程执行方法的过程对应的是栈帧的进栈以及出栈的过程。所以可以知道,栈帧实际上记录的就是方法的信息,比如局部变量表,动态链接,方法出口等信息。局部变量表存放的是基本数据类型以及对象引用。
如果请求栈的深度超过允许的栈深度,则会抛出StackOverFlowError的异常。
本地方法栈
本地方法栈跟虚拟机栈是对应的,如果执行的不是Java的方法,那么就是在本地方法栈进行操作,同样会抛出StackOverFlowError的异常。
Java堆
Java堆是在虚拟机启动的时候创建并划分大小的,Java堆的大小是可以通过参数进行控制的,设置Xmx跟Xms参数,空闲程度大于70%就调整到小的,小于40%就调整到大的,因为如此设置的话课比较频繁,所以很多case下都是设置为一样大小。
Java堆主要存放的是对象以及数组。
方法区
方法区同样是线程共享的,分为两部分。方法区主要存放的是类信息,而里面还有一个运行时常量池,用于存放编译产生的字面量以及符号引用。
三、如何创建对象
Java作为一门面向对象语言,每时每刻都在产生对象。在语言层面,用到的是一个new关键字,但是在背后存在着复杂的逻辑。
Java虚拟机遇到一个new操作的时候,会先去常量池里面查看能否定位到一个符号引用,并检查该符号引用对应的类是否被加载、解析以及初始化过,如果没有则执行类加载的过程。
创建对象的方式
在不同的虚拟机上有不同创建对象的方式,主要有以下两种。指针碰撞
假设在内存都是规整的前提下,内存分为两块,一块是已经使用的区域,一块是待分配的区域。指针位于两个区域的中间,当需要分配内存的时候,计算需要分配的对象的大小,然后进行划分一个区域空间进行分配即可。
内存记录
但是实际情况总是不是那么美好的,内存不可能一直都是工整的,在这个时候就需要有一个列表,记录着内存中哪一块是空闲的区域,当需要分配的时候,在内存列表上进行查找,分配一个足够大的内存进行分配。