1. 运行时数据区域
1.运行时数据区域
分为五个区域,分别是方法区,虚拟机栈,本地方法栈,堆,程序计数器
1. 程序计数器
程序计数器是一个较小的内存区域,它可以看作是当前线程所执行的字节码的行号指示器,在Java虚拟机的概念模型中,字节码解释器工作时,就是通过改变计数器的值来执行下一条指令。
又因为虚拟机的多线程是通过个线程之间的轮换,分配处理器执行时间来实现的,在每一个时刻,都有在执行的线程中的指令,因此为了线程在切换回来之后,都能够找到准确的位置,因此各个线程中的计数器都是互不影响,独立存储的,我们称之为线程私有的内存。
2. Java虚拟机栈
Java虚拟机栈也是线程私有的,他的生命周期和线程的生命周期相同,Java虚拟机栈描述的是Java方法执行的线程内存模型:每一个方法执行的时候,Java虚拟机都会创建一个栈帧用于存储局部变量表,每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程
其中Java内存区域常被划分的堆和栈,其中的栈就是指Java虚拟机栈。
其中虚拟机栈中的局部变量表存放了编译期可知的各种Java虚拟机基本数据类型,对象引用数据类型,这些数据类型在局部变量表中的存储空间以局部变量槽来表示。
在Java虚拟机规范中,对这个内存区域规定了两类异常情况:如果线程请求的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常,如果Java虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存会抛出OutOfMemeryError异常
3. 本地方法栈
本地方法栈和虚拟机栈所发挥的作用是非常相似的,其区别是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则是为虚拟机使用到的本地方法服务,和虚拟机栈一样,如果线程请求的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常,如果Java虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存会抛出OutOfMemeryError异常
4.Java堆
对于Java应用程序而言,Java堆是虚拟机所管理的内存中最大的一块,Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建,此内存区域的唯一作用是存放对象实例,在Java中,几乎所有的对象实例都是在这里分配内存,而现今随着逃逸分析技术的日渐强大,栈上分配,标量替换优化手段已经导致一些微妙的变化,所以如今说Java所有的对象都是分配在堆上也渐渐变得不是那么绝对了。
Java堆也是垃圾收集器管理的内存区域,因此有时称之为GC堆,现在的垃圾收集器大部分都是基于分代手机理论设计的,所以Java堆中常会出现“新生代”之类的词,但是这些区域的划分只是一部分垃圾收集器的特性,并不是莫格Java虚拟机具体实现的固有内存布局
从内存分配角度看,所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区,以此提高对象分配时的效率,不过无论发生何种情况都不会改变Java堆中的存储共性。
Java可以存储在物理地址上不连续的地方,但是他在逻辑地址上必须是连续的。
Java堆既是可以被实现成固定大小的,也可以是可扩展的,不过当前主流的Java虚拟机都是按照可扩展来实现的。
5.方法区
方法区和Java堆一样,是各个线程共享的内存区域,它用于存储已经被Java虚拟机加载的类型信息,即时编译器编译后的代码缓存等数据。
- 运行时常量池
运行时常量池时方法区的一部分,Class文件中除了有类的版本,字段,方法,接口等描述信息之外,还有一项信息就是常量池表,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后存放在方法去的运行时常量池里
运行时常量池相对于Class文件常量池的一个重要特征就是具备动态性,Java语言并不是要求常量一定只有编译期才能产生
2. 直接内存
直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这一部分内存也被频繁的使用,而且也可能导致OutOfMemoryError异常的出现,本机直接内存的分配不会受到Java堆的大小的限制,但是会受到本机总内存大小的限制。