Java虚拟机所管理的内存包括的数据区域
- 程序计数器
- 虚拟机栈
- 本地方法栈
- 方法区(线程共享)
- 堆(线程共享)
程序计数器
- 它是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器
- 每一个线程都会有一个独立的程序计数器,即线程私有
虚拟机栈
- 线程私有,它的生命周期与线程相同
- 它描述的是Java方法执行时的线程内存模型
- 当一个方法被执行时,JVM会为其同步创建一个栈帧,一个方法的执行过程,就对应着一个栈帧再虚拟机栈的入栈到出栈的过程
本地方法栈
- 与虚拟机栈功能类似,不同的是虚拟机栈为Java方法服务,而本地方法栈则是为虚拟机使用到的本地方法服务
堆
- Java堆是线程共享的,它存放的是对象实例,几乎所有的对象实例都在堆中分配内存
- Java堆是GC管理的内存区域
方法区
- 线程共享
- 它用于存储已被JVM加载的类型信息、常量、静态变量、即编译后代码缓存等数据
- 运行时常量池是其中一部分
JVM中对象的创建
我们在创建对象时通常是使用的仅仅是一个new关键字,然而在这背后,JVM为我们做了很多事。
- 首先要检查new指令的参数是否在常量池中可以定位到一个类的符号引用,然后检查这个类是否已经完成类加载过程,如果没有,则先执行类加载
- 类加载完成之后,就要为新对象在Java堆中分配内存。如果内存空间是规整的,那只需要将指示内存空闲空间和已经分配空间的边界指针,向空闲方向移动相应的空间即可,这种方式称为“指针碰撞”;但如果内存空间是不规整的,那么虚拟机就需要维护一个空闲列表,分配时从列表找到一块足够大的空间进行分配,并更新列表,这种方式称为“空闲列表”。
- 除了分配空间之外,还需要考虑并发的问题,JVM采用的方式是采用CAS机制配上失败重试的方式来保证操作的原子性
- 得到内存空间之后,JVM会将分配到的内存空间都初始化为零值,然后在对象的对象头中存入一些信息,如这个对象是哪个对象的实例,哈希码等。
- 完成1-4步后,从虚拟机的视角,一个对象已经产生了,但是这个时候所有的字段还是默认的零值,构造函数还没有执行,所以new指令之后会执行()方法,这样一个真正的对象才算被构造出来。