JVM内存区域

参考:深入理解Java虚拟机(第2版)

简单概述JVM有哪些内存区域,以及他们的功能

主要是七个区域:

  1. 程序计数器
  2. Java虚拟机栈
  3. 本地方法栈
  4. Java堆
  5. 方法区
  6. 运行时常量池
  7. 直接内存

1.程序计数器

程序计数器是一块较小的内存区域,我们可以将它看作是一个记录当前代码运行到什么位置的行号指示器。
但是这个指示器并不是直接指定某行代码,而是将Java文件编译后的class文件,也就是字节码文件(十六进制),是记录字节码执行到哪一行。所以字节码解释器工作时,就是通过改变这个计数器的值来选取下一条需要被执行的字节码指令。分支循环跳转异常什么的,都靠这个计数器来完成。
每一个线程都有一个属于自己的程序计数器,各个线程的计数器互不影响,独立存储。但如果当前执行的是native方法,这个计数器则为空。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

2.Java虚拟机栈

这个东西也是线程私有的东西。每个线程在执行的时候,都会创建一个栈帧,这个东西主要用来存储局部变量表
、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程

栈帧里面的局部变量表存放的都是一些编译期可知的各种基本数据类型,boolean、byte、int啥的,对象引用和returnAddress类型(指向一条字节码指令的地址)。如果线程请求的栈深度大于虚拟机所允许的深度,就会抛StackOverflowError异常。如果虚拟机栈可以动态扩展,知道无法继续扩展为止都满足不了线程请求的栈深度,那么就会抛OutOfMemoryError异常。

3.本地方法栈

这玩意儿跟Java虚拟机栈差不多,区别就是本地方法栈是为native方法工作的,不过现在有很多虚拟机把本地方法栈和虚拟机栈合二为一了。

4.Java堆

这东西是Java虚拟机所管理的内存中最大的一块,而且这个东西是被所有线程共享的。这个内存区域唯一的目的就是存放对象实例和数组,几乎所有的对象实例都要在这里分配内存。由于这个区域很大,所有我们著名的垃圾回收,主要管理的区域就是这个区域。如果这个区域的东西填满了,也会抛出OutOfMemoryError异常。

5.方法区

跟Java堆一样,也是一个各个线程共享的内存区域,主要存储被虚拟机加载的类的信息、常量、静态变量、即时编译器编译后的代码等数据。他还有一个别名(Non-Heap)非堆,估计是跟Java堆做区分。这个也是内存不够的时候会抛出OutOfMemoryError异常。

6.常量运行池

这的区域其实是方法区的一部分,听名字就能猜到主要是存放编译期生成的各种字面量和符号引用。不一定是在编译器,就把所有的常量放进来,在运行期间也可以把新的常量放到池中,比如使用String的intern()方法。这是方法区的一部分,所以内存不够的时候也会抛出OutOfMemoryError异常

7.直接内存

老实说直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但这部分内存被频繁使用,而且也会导致OutOfMemoryError异常出现,所以我们放到这里一起讲解。
JDK1.4有个NIO类,引入一种基于通道与缓冲区的IO方式,它可以使用native函数库直接分配堆外内存,所以直接内存不会受到Java堆大小的限制,但既然是内存,还是会受到本机总内存的大小以及处理器寻址空间的限制。所有还是会出现OutOfMemoryError异常。

你可能感兴趣的:(Java)