java内存空间
其中如图中所展示的,按功能分了大致分为两类,一类为线程共享的JAVA堆和元数据区和直接内存,另一类是线程私有的虚拟机栈,方法区栈和程序计数器。
下面针对这几种区域来详细将这几个区域分别的作用是什么。
程序计数器
程序计数器是一块较小的内存空间,可以看作是当前线程执行程序的字节码的的行号的指示器。字节码解释器工作时通过改变程序计数器的值来改变将要选取的下一个指令。并且由于每个线程执行的运行的指令不同,每个线程有个字的程序计数器,并且互不干扰。所以程序计数器被称作是线程私有的。这种线程私有的区域有着很明显的特征就是生命周期和当前线程的周期保持一致。并且需要注意的是程序计数器是内存中唯一一个不会出现outOfMemory
的区域。
程序计数器有两个作用:
A: 字节码解释器通过读取程序计数器的值来选取下一条将要执行的语句。
B:在多线程切换的情况下,记录当前线程执行的位置,方便于切换回时进程运行的位置。
虚拟机栈
Java内存可以粗糙的分为堆内存和栈内存,所谓的堆就是图中的java堆(Heap
),而所谓的栈就是指的虚拟机栈(VM Stack
)的局部变量表。虚拟机栈是由一个个栈针构成的,可以想为一个方法为一个栈针,随着方法的被调用完成(完成的条件有两个,一个是return,另外一个是发生异常),对应着方法的栈针出栈。栈针中都包含:局部变量表,操作数栈,动态链接和方法出口。局部变量表主要存放了编译器可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)
本地方法栈
本地方法栈同样是线程私有的,区别是java虚拟机栈是用于java字节码的,而本地方法栈是用来执行Native方法的.结构都和虚拟机栈的结构相同.
Java堆
Java堆是整个虚拟机中最大的一块区域,是线程共享的区域,再虚拟机启动时创建,该块存在的唯一目的就是存放类的事例和数组.
方法区
和Java堆一样都是线程共享的区域,主要用于存放已经被虚拟机加载的类信息,常量,静态变量和已经被编译后的代码等数据.方法区和永久代的关系很像Java中接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方式。 也就是说,永久代是HotSpot的概念,方法区是Java虚拟机规范中的定义,是一种规范,而永久代是一种实现,一个是标准一个是实现,其他的虚拟机实现并没有永久带这一说法。
运行时常量池
原来的运行时常量池是方法区的一部分,而在1.7之后,讲运行时常量池放到堆(Heap)中开辟了一个区域专门用来放运行时常量池.运行时常量池中遥遥包括两部分,一部分是实际存在的字面量,所谓字面量包括[1.文本字符串,2.被声明为final的常量,基本数据类型…..],另一部分是符号引用,包含[类和结构的名称,字段的名称,方法的名称]
元数据区
替代了永久代,使用的是直接内存,什么是直接内存,它有能够干什么? 首先直接内存区域不是虚拟机运行时数据区的一部分,也不是虚拟机定义的一部分,但是经常会使用到.
JDK1.4 中新加入的 NIO(New Input/Output) 类,引入了一种基于通道(Channel) 与缓存区(Buffer) 的 I/O 方式,它可以直接使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样就能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆之间来回复制数据。
本机直接内存的分配不会收到 Java 堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。
对象的创建过程
对象的创建过程分为上图中的5步
- 类加载检查:当虚拟机遇到new的时候,会检查这个类是否存在,是否被加载,解释和初始化过,如果没有则进行类的初始化过程.
- 分配内存:再进行类加载检查后,会在堆内存中为新的对象分配内存,分配的规则有两种,一种是指针碰撞,另一种是空闲列表,针对不同的垃圾回收器会使用不同的方法.第一种方法指针碰撞的原理大致为它会将分配过的内存和未分配的内存间建立一个指针,当分配内存的时候,向为分配内存的地方移动新的对象的大小的位置,适用于比较规整的内存空间.第二种方法是维护一个分配内存的列表,每次分配内存都想列表中添加相关记录,表明这些对象在哪.
- 初始化零值:保证在分配完内存后,为分配的内存区域初始化为零值
- 设置对象头:虚拟机对对象的各种设置信息,保存在对象头中.
- 执行init方法:在执行init方法前,从虚拟机的角度来看其实对象已经生成了,但是在程序员的角度对象并没有生成,只有在init方法执行过后,对象才算生成.
对象的定位方式
Java虚拟机定位对象的方式主要有两种,一是使用句柄,二是直接使用指针.