根据Java虚拟机规范的定义,JVM的运行时内存区域主要由程序计数器、虚拟机栈、本地方法
栈、Java堆、方法区和以及运行时常量池组成。其中堆、方法区以及运行时常量池是线程之间共享的区域,而栈(本地方法栈+虚拟机栈)、程序计数器都是线程独享的。
程序计数器:是用来存储指向下一条指令的地址,也即将要执行的指令代码,由执行引擎读取下一条指令,是线程私有的 、不会存在内存溢出。
Java虚拟机栈:一种线程私有的存储器,用于存储Java中的局部变量,每次方法调用都会创建一个栈帧,该栈帧用于存储局部变量,操作数栈,动态链接,方法返回地址等信息。当方法执行完毕之后,这个栈帧就会被弹出,变量作用域就会结束,数据就会从栈中消失。
本地方法栈:本地方法栈中存放本地方法(Native Method)的参数和局部变量,以及其他于些附加信息。这些本地方法一般是用C等本地语言实现的,虚拟机在执行这些方法时就会通过本地方法栈来调用这些本地方法
Java堆:是存储对象实例的运行时内存区域,几乎所有的对象实例都要在上面分配内存,占据着虚拟机内存总量的一大部分。此外,Java堆还用于垃圾回收,虚拟机发现没有被引用的对象时,就会对堆中对象进行垃圾回收,释放内存空间。
方法区:用于存储已被加载的类信息、常量、静态变量、即时编译后的代码等数据的内存区
域。每加载一个类,方法区就会分配一定的内存空间,用于存储该类的相关信息,这部分空
间随着需要而动态变化。方法区的具体实现形式可以有多种,比如堆、永久代、元空间等。
运行时常量池:是方法区的一部分。用于存储编译阶段生成的信息,主要有字面量和符号引
用常量两类。其中符号引用常量包括了类的全限定名称、字段的名称和描述符、方法的名称
和描述符。
Java 8及之后堆内存逻辑上分为三部分:新生区+养老区+元空间
新生区:由年轻区(Eden)、Survivor区组成(From Survivor、ToSurvivor)。默认情况下,新生代的Eden区和Survivor区的空间大小比例是8:2,可以通过参数调整。
为什么分代:Java中的大部分对象都是朝生夕死的,同时也有一部分对象会持久存在。如果把这两部分对象放到一起分析和回收,这样效率实在是太低了。通过将不同时期的对象存储在不同的内存池中,就可以节省宝贵的时间和空间,从而改善系统的性能。
方法区是Java虚拟机规范定义的一块用于存储类信息、常量、静态变量、编译器编译后的代
码等数据的内存区域。方法区时一种规范,而永久代和元空间是它的一种实现方式