一 运行时的数据区组成
程序计数器
当前线程执行的字节码的行号指示器。自己吗解释器通过改变程序计数器(PC)的值来选取下一条需要执行的字节码指令。分支、循环、跳转、线程回复等基础功能都依赖于它。
例如:Java多线程机制。线程轮流切换,分配CPU执行时间,任一时刻,一个CPU只会执行一条线程指令,每个线程都需要一个独立PC,以保证线程切换后能正确恢复。虚拟机栈四点说明:
- 生命周期随着线程存亡
- Java方法执行的内存模型:每个方法在执行的同时会创建一个线帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
- 每个方法从调用直至执行完成的过程,就对应着一个线帧在虚拟机栈中从入栈到出栈的过程。
- 能发生的两类异常:
- I:线程的请求深度大于虚拟机所允许的深度,会抛出StackOverflowError。
- II:虚拟机栈可动态扩展时无法申请到足够的内存,就会抛出OutOfMemoryError。
本地方法栈
作用与虚拟机相同,不同的是虚拟机栈为虚拟机执行Java方法(即字节码)服务,而本地方法栈为虚拟机执行本地方法(Native)服务。Java堆
Java Heap是Java虚拟机所管理的内存中最大的一块,是所有线程共享的一块内存区域。在虚拟机启动时创建,此区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
说明:
- 是垃圾收集器管理的主要目标(GC Garbage Collected).
- 可以处于物理上不连续的内存空间中,只要逻辑上连续即可。
5.方法区
与堆一样,是所有线程共享的内存区域。它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
运行时常量池(Runtime Constannt Pool):是方法区的一部分。Class文件中除了有类的版本、方法、字段、接口等描述信息外,还有一项是常量池,用于存放编译期间生成的各种字面两和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
运行时常量池相对于class文件常量池的另外一个特征是动态性,Java语言并不要求常量一定是编译器才能产生。运行期间可将新的常量放入池中,比如String的intern()方法就是这种特性的直接应用。
- 直接内存
非虚拟机运行时数据区的一部分,但频繁使用
来源:JDK 1.4之后引入NIO类,引入一种基于通道(Channel)与缓冲区(Buffer)的I/O方式。它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。由于避免在Java堆和Native堆中来回复制数据,在某些场合可显著提高性能。
二 Java内存模型与线程
- 主要目标
定义程序各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量的底层细节。注意:
- 此处的主内存、工作内存与上面的Java堆、栈、方法区等不是同一层次的划分,两者没有关系
2.内存模型与线程的对应关系如下图:
- 说明
- Java内存模型规定所有变量都存储在主内存中,此处主内存仅是虚拟机内存的一部分.
- 每个线程还有自己的工作内存(作用类似于处理器告诉缓冲),线程的工作内存保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。