运行时数据区域java
Java虚拟机在执行Java程序过程当中把所管理的内存划分为如下几个不容的数据区域,这些区域都有各自的用途,以及建立时间和销毁时间。
程序员
程序计数器、虚拟机栈、堆、方法区、本地方法栈算法
程序计数器数组
背景:java 多线程是经过线程轮流切换并分配处理执行时间来实现,在任何一个时刻,一个处理器只会执行一条线程的指令。所以须要用一块内存空间记录线程的执行状态,这就是程序计数器。多线程
存储的内容:存放程序下一条指令的地址地方。布局
目的:为了线程切换后可以恢复到正确的执行位置,每条线程都有一个独立的程序计数器。(惟一一个没有没有OutOfMemeryEror状况的区域)。“记录现场,恢复现场”spa
java虚拟机栈线程
存放内容:局部变量表、操做数栈、动态连接、方法出口(线程私有,生命周期与线程相同。)指针
虚拟机栈:是Java方法执行的内存模型。每一个方法在执行的同时都会建立一个栈帧用于存储局部变量表、操做数栈、动态连接、方法出口。orm
生命周期:每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中的的入栈到出栈过程
局部变量表存放了编译期可知的各类基本数据类型、对象引用和returnAdderss类型
当进入一个方法时,这个方法所须要在帧中分配多大的局部变量空间是彻底肯定的。方法运行期间不会改变局部变量表的大小
Java虚拟机规范中对这个区域定义了两种异常情况:StackOverflowError(线程请求栈深度 > 虚拟机所容许的深度)。OutOfMemoryError(若是Java虚拟机动态扩展没法申请足够内存的时候)
本地方法栈
与虚拟机栈一致,惟一区别虚拟机栈为 java 方法服务。本地方法栈是为 native 方法服务。
Java 堆
目的:惟一目的就是存放对象实例,几乎全部的对象实例都在这里分配。
Java 堆是Java虚拟机所管理的内存中最大的一块。
Java堆是被全部线程共享的一块内存区域,在虚拟机启动的时候建立。
Java 堆是垃圾回收器管理的主要区域,所以也被称为“GC堆”(垃圾堆)。
分类:因为如今垃圾收集器基本采用分代收集算法,因此Java堆中还能够分为:新生代,老年代;再细致一点还有 Eden空间、From Survivor 空间、 To Survivor空间。
根据Java虚拟机规范,Java堆能够处于物理上不连续的内存空间中,只要逻辑连续便可
若是堆中没有内存完成分配实例,而且堆也没法扩展,将会抛出OutOfMemory异常
方法区
存储对象:它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码。方法区也被称为永久带
与Java堆同样,是各个线程的共享的内存区域。
深刻探讨Hotspot虚拟机在Java堆中的对象分布,布局和访问的过程
对象的建立
虚拟机遇到 new 指令时候,首先检查指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用表明的类是否已经被加载、解析、初始化。若是没有,那必须执行相应的类加载过程
在类加载经过后,虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后即可以彻底肯定。
Java 堆为对象分类内存的两种方式
指针碰撞:假设java堆是绝对规整的,全部用过的内存放在一边,空闲的内存放在另外一边,中间放着一个指针做为分界点的指示器,分配内存就仅仅是把指针向空闲空间那边挪动一段与对象大小相等的距离
空闲列表:若是Java 堆并非规整的,已使用的内存和空闲内存相互交错,虚拟机就必须维护一个列表,记录哪些内存块是可用的。
选择哪一种方式取决于Java堆是否规整,而Java堆是否规整又取决于垃圾收集器是否带有压缩整理功能决定。
内存分配完成后,虚拟机须要将分配到的内存空间都初始化为零值
虚拟机对对象进行必要设置,例如找个对象是哪一个类的实例,如何才能找到类的元数据信息,对象的哈希码、对象的GC分代年龄。这些信息都存放在对象的对象头中。
从虚拟机视角来看,一个新的对象已经产生,但从Java程序视角来看,对象建立才刚刚开始--<init>方法尚未执行。全部字段都仍是零。执行new指令以后会接着执行<init>方法,把对象按照程序员的意愿进行初始化。这样一个真正的对象才算彻底产生。
总结:JVM遇到new指令 —> 检查指令参数,与常量池中类符号引用匹配 & 检查类是否被加载 —> Java 堆为对象分配内存(分配内存两种方式)—> 内存空间初始化为零 & 对对象进行必要设置—> 执行init方法
对象的内存分布
对象在内存中存储的布局能够分为3个区域:对象头,实例数据,对齐填充
对象头:包含用于存储对象自身的运行时数据,类型指针
自身运行时数据:HashCode 哈希码、GC分代年龄、锁状态标识、线程持有的锁、偏向线程ID、偏向时间戳。
类型指针:对象指向它的类元数据的指针。若是对象是一个Java数组,那么对象头中还必须存储数组长度。
实例数据:对象真正存储的有效信息,也是程序代码中所定义的各类类型的字段内容。
对齐填充:仅仅起占位符的做用。HotSpot VM 的自动内存管理系统的要求对象起始地址必须是8的整数倍,也就是说对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的整数倍。因此对象实例部分没有对齐时,就须要经过对齐填充来补全。
对象的定位访问
产生背景:Java 程序须要经过栈上的reference数据来操做堆上的具体对象。因为reference类型在Java虚拟机规范中只规定了一个指向对象的引用,并没有定义这个引用该经过何种方式去定位、访问堆中的对象的具体位置。
定位方式:句柄、直接指针。
句柄:Java堆中将会划分出一块内存做为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。