本文我们将讲解Java虚拟机中各个区域以及各个区域的作用。

一.程序计数器
什么是程序计数器,有什么作用?
程序技术器是一块比较小的内存区域,主要当做是线程中所执行的字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值来选取下一个执行的字节码命令,分支、循环、跳转等基础功能都是依赖这个程序计数器来完成。

有什么特点?
Java虚拟机中的多线程是通过线程轮流切换分配处理器执行时间的方式来实现的,所以为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,所以是线程私有的。

注意:
如果线程执行的是Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器的值为空,此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemory的情况的区域

二.Java虚拟机栈
Java虚拟机栈是干嘛的?
Java虚拟机栈描述的是Java内存模型,每个方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法返回地址等信息。每一个方法从调用到执行结束对应着一个栈帧在虚拟机栈中入栈出栈的过程。

有什么特点?
Java虚拟机栈是线程私有的,而且生命周期和线程相同。

注意:
如果线程请求的栈的深度大于虚拟机所允许的深度,将抛出StackOverFlowError异常;如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够多的内存,就会抛出OutOfMemoryError异常。

三.本地方法栈
与虚拟机栈发挥的功能类似,区别不过是虚拟机栈为虚拟机执行Java方法,本地方法栈为虚拟机用到的Native方法服务。本地方法栈也会抛出StackOverFlowError和OutOfMemoryError异常。

四.Java堆
什么是Java堆,有什么作用?
Java堆是Java虚拟机中所管理内存中最大的,是所有线程共享的一块内存区域,在虚拟机启动的时候创建,目的是存放对象实例。

有什么特点?
几乎所有的对象实例都在这里分配内存,因此这也是垃圾收集器管理最主要的区域,而且Java堆可以处于物理不连续的内存空间,只要逻辑连续即可

1、Java堆中还细分新生代和老年代,然后新生代中又分为Eden区域、From Survivor空间、To Survivor空间等。

2、这里的Java堆的垃圾回收算法是使用了分代收集算法,即新生代中使用“复制”算法,而老年代中使用“标记-清理”算法或“标记-整理”算法。

注意:
当前主流虚拟机都是可扩展来实现的(通过-Xms和-Xmx来控制),如果堆中没有内存完成实例,并且堆也无法再扩展时,会抛出OutOfMemoryError异常。

五.方法区
方法区的作用是什么?
方法区是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。

为啥说方法区不等价于永久区?
方法区不等价于永久代,只是HotSpot虚拟机的设计团队选择把GC分代收集扩展至方法区,是为了HotSpot垃圾收集器可以像管理Java堆一样管理这部分内存,能够省去专门为方法区编写内存管理代码的工作,但是这样也会更容易造成内存溢出的问题(永久代可以用-XX:MaxPermSize设置上限),所以在JDK1.7的HotSpot已经把永久代的字符串常量池移出,移到了Java Heap区,可在 《深入解析String#intern》 了解

运行时常量池有什么作用?
运行时常量池也是方法区的一部分,用于存放编译期生成的各种字面量和符号引用,这部分将在类加载后进入方法区的运行时存放。

运行时常量池的特点?
Java虚拟机对Class文件每一部分的格式都有严格规定,每一个字节用于存储哪种数据都必须符合规范上的要求才会被虚拟机认可、装载和执行,然而对于运行时常量池却没做任何要求
运行时常量具有动态性,可以在运行期间将新的常量放入池中,比如String的intern()方法
六.直接内存
直接内存是Java虚拟机的内存吗?
直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范定义的内存区域,是使用本机的内存,又名堆外内存。

怎么在Java中使用堆外内存?
在JDK1.4中的NIO类,引入了基于通道(Channel)与缓冲区(Buffer)的I/O方式,可以使用Native函数库来直接分配堆外内存,然后在Java堆中使用DirectByteBuffer对象来作为这块内存的引用进行操作。

注意:
虽然堆外内存不受Java堆大小的管理,但是受本机总内存以及处理器寻址空间的限制。在服务器管理员配置虚拟机参数的时候,可以通过-Xmx等来配置Java虚拟机最大内存,但经常忽略直接内存,导致各个内存区域总和大于物理内存限制,导致OutOfMemoryError异常。

如果本文有什么疑问或者是错误,欢迎指出留言,互相学习