Java虚拟机在执行Java程序时会把它所管辖的内存划分为若干个区域,这些区域各有用途,生命周期也各自不同。
1、程序计数器 。是每条线程 都有的一小块私有区域 。在程序执行时,一个CPU内核内只能有一条线程执行,不会有多条线程并行执行,但是会有多条线程在该内核轮流执行,即并发执行,这就要求每条线程都要记录自己已经执行到的位置,方便下次轮到CPU时间片时可以继续执行。程序计数器就是记录这条线程执行位置的。这块区域是Java虚拟机规范中唯一没有规定任何OutOfMemoryError的区域。
2、Java虚拟机栈 。也是线程私有。每条线程都有这么一个栈,每个方法在执行时都会创建一个栈帧(存放着局部变量、动态链接等信息)并压入该虚拟机栈,方法执行完毕就又从该栈里将栈帧弹出。如果压入的栈帧太多,就会发生栈溢出异常 StackOverflowError。
线程记录方法的数据结构为什么用栈呢?
试想,线程在执行的时候,方法的调用顺序是 方法1 -> 方法2 -> 方法3 -> ... 这种嵌套调用,而且最后被调用的那个方法执行完毕后也就又返回到了上一个调用的方法,也就是方法调用是一种 后进先出 的顺序,恰好符合 栈 的形式。
为什么要对栈的深度做限制呢?
每条线程都有这么一个虚拟机栈区域,它是一块内存,但是内存是有限的呀,如果不做限制,内存就会很快耗完,尤其如果程序出错导致出现无限循环调用方法(比如递归)的时候,这块栈区就会一直增大。
3、本地方法栈。与虚拟机栈作用类似,也是线程私有的,只是它是线程存放本地方法的栈帧的。
**4、Java堆。**这里就是所有线程共用的区域了,大家可能也对这块最熟悉------这里就是几乎所有对象的实体数据的存放位置。
5、方法区。 也是所有线程共用的区域。这里存放虚拟机加载的类的各种静态常量、类的信息(父类、类名、访问修饰符等)、即时编译器编译后的代码(即本地机器码)等数据。Java虚拟机规范中把它描述为堆的一个逻辑部分。
为什么叫方法区(Method Area)?这个名字有点风马牛不相及
确实,如果叫 类元数据区 会更合适,之所以叫方法区是个历史原因。在Java初期,这块内存区域主要用于存储方法字节码和方法表,因此得名 "方法区"。当时 Java 语言特性相对简单,方法是程序执行的核心单元,这个命名直观反映了其核心功能。
6、运行时常量池。它是方法区的一部分。用于存放编译期生成的各种字面量和符号引用(如类和接口的全限定名、字段名、方法名等)。运行时常量池就是每个类的"常量与符号引用表",是 Class 文件中常量池表的内存版本,供 JVM 执行字节码时快速查找和使用。
7、直接内存。它并不是Java虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是由于被频繁使用所以特意说一下。使用直接内存进行 I/O 操作(如文件、网络)时,JVM 可以直接将数据写入本地内存,省去了从 Java 堆到本地内存的中间拷贝 ,提升性能,但是分配较慢,释放代价高。