一、Java的内存区域(理论部分)
Java虚拟机在执行Java程序的时候把它所管理的内存分为多个不同的区域,这些区域归纳为两种:线程共享区和线程隔离区。
1、线程共享区
线程共享区包括了:方法区和堆,这个区域随着虚拟机的启动而创建。
堆,是Java虚拟机所管理的内存中最大的一块,存放对象实例和数组,Java堆还可以细分为新生代和老年代,新生代包括:Eden空间,From Survivor空间,To Survivor空间等,在物理上,java堆是处于不连续的内存空间,逻辑上连续即可;拓展可通过配置-Xms和Xmx控制;
方法区:存储已被虚拟机加载的类信息、常量池、静态变量以及及时编译器编译的代码等数据;这块区域的垃圾回收主要针对常量池的回收和对类型的卸载;
2、线程隔离区
线程隔离区包括了:VM Stack(虚拟机栈)、Native Method Stack(本地方法栈)、Program Counter Register(PC 计数器)。线程隔离区的生命周期是随着线程的创建而存在,结束而销毁;
VM Stack(虚拟机栈),为Java虚拟机执行Java方法服务,描述的是Java执行时的内存模型:每个方法在执行时都会创建一个栈帧,用于存储局部变量、操作数栈、动态链表以及方法出口等信息;局部变量表在编译的时候完成内存空间分配,存放的是基础数据类型、对象引用以及return Address类型(指向字节码指令的地址)。
Native Method Stack(本地方法栈):为Java虚拟机执行本地方法服务,存放数据类型与虚拟机栈相似;
Program Counter Register(PC 计数器):内存空间比较小,存放的是当前线程所执行的字节码行数;这里涉及到了多线程的原理:由于多线程是线程轮流切换并分配处理器执行时间实现的,在任何一个时刻,一个处理器(内核)只会执行一条线程中的指令,为了能使切换先后恢复到正确的执行位置,所以每个线程都有自己独有的PC计数器。
二、对象的创建
Java中创建一个对象是,是通过new 关键字实现,在虚拟机中的过程,是这样的:
虚拟机遇到一条new指令时,先检查这个指令的参数是否在常量池中有类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过,如果没有,先执行相应的类加载过程。类加载过程检查通过后,对象所需的内存大小在类加载过程中已确定,此时虚拟机则为其分配内存空间,内存分配完成后,虚拟机将分配到的内存空间都初始化为零值(不包括对象头)——这里保证了对象的实例字段值在Java代码中不赋初始值就直接使用,程序访问到的是这些字段的数据类型所对应的零值,然后对象进行一些设置,比如:这个对象是哪个对象的实例,如果找到对象的元数据信息,对象的哈希码,对象GC分带年龄等信息,这些信息存在对象头中。至此,虚拟机创建对象已完成。紧接着,执行<init>方法,将对象在Java程序中进行初始化。
备注:本章节内容参考了《深入理解Java虚拟机》