JVM内存模型
正如阅读《深入理解Java虚拟机》一书看到的:(C/C++)墙外的人想进来,(Java)墙内的人想出去。那么我们来看看,Java怎么围起来的这道墙?
JVM内存模型
- Java不需要像C/C++那样自己管理内存.Java的内存都是由JVM统一管理的.Java中的new关键字就可以申请内存了.但是Java仍然会出现内存泄漏的情况,如果长时间持有对象而不进行释放,就会造成内存泄漏.
JVM内存模型中分为了线程私有的组件和线程共享的组件.
首先了解一下线程,线程是值程序在执行过程中的一个线程实体,JVM允许一个实体也即是一个进程,并发的执行多个线程.Hotspot JVM中的java线程与原生操作系统线程有直接的映射关系.
线程私有内存区域
程序计数器(PCR)
- 程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器.字节码解释器在工作的时候,通过对这个计数器的值进行改变,来选取下一条需要执行的字节码指令,Java中的分支,循环,跳转,异常处理,线程恢复等等基础功能,都需要通过这个计数器来完成.
- 所有的线程自己都有一个pcr,典型状态下,每执行一条指令pcr都会自增,而pcr正好存储了下一条需要执行的指令.
- java虚拟机的多线程执行是通过线程之间的相互切换执行的.因为对于一个处理器,一次只会执行一条线程中的指令.
本地方法栈
- 本地方法栈是为虚拟机中使用到Native方法服务,它和虚拟机栈区别不大。有的虚拟机比如Sun HotSpot虚拟机,直接把本地方法栈和虚拟机栈合二为一了。
- 同样该方法也会抛出StackOverflowError和StackOverflowError异常。
虚拟机栈
- 每个java方法被执行时,在线程中都会创建一个栈帧,该栈帧用来存储局部的变量表,操作栈,动态链接,方法出口等信息。栈帧的入栈出栈对应着一个方法的执行开始和执行结束。
- 有人通常将java内存成为堆(Heap)和栈(Stack),这里栈就是虚拟机栈,是线程私有的一个存储区。
- 局部变量表(虚拟机栈)的内存大小在编译期就会事先分配好。所以,由于其内存大小的固定性,线程在执行方法时,如果嵌套的方法层数过深(栈深度大于虚拟机所允许的深度),将会抛出StackOverflowError异常。当然,现在的Java虚拟机都允许动态扩展虚拟机栈的大小,不过申请不到足够的内存的结果是StackOverflowError异常。
线程共享内存区域
Java堆
- Java虚拟机最大的一块内存区域,在虚拟机启动时创建。该内存区域的唯一目的是存放对象实例。
- Java堆时常面临着垃圾收集。so,有的地方也叫做GC堆。目前的垃圾收集器一般采用的算法是分代收集算法。所以,Java堆还可以分为:新生代和老年代。
方法区
- 方法区也是被各个线程共享的内存区域,它主要存储的是已经被虚拟机编译的类信息,常量、静态变量以及即时编译器编译后的代码等数据。
运行时常量池
- 运行时常量池是方法区的一部分。顾名思义,它是用来存放编译期生成的各种字面量和符号引用。
直接内存
- 直接内存不是java虚拟机规范定义中的内存区域。他是直接能被java进程使用的外部内存。比如在NIO模型中,使用的Native函数库直接分配就是堆外内存,这样程序直接使用的系统内存,避免了从Native堆和Java堆数据的来回复制。我记得Netty中就使用到了直接内存,极大的提高了数据的传输速度。
网友评论