Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域,
包含程序计数器, 虚拟机栈, 本地方法栈, Java 堆, 方法区(运行时常量池), 直接内存等, 不同的版本会有所差异
各区域的作用:
1, 程序计数器: 较小的内存空间, 当前线程执行的字节码的行号指示器; 各线程之间独立存储, 互不影响;
2, 虚拟机栈: 线程私有, 生命周期和线程同生共死, 每个方法在执行的同时都会创建一个栈帧用于存储局部变量表, 操作数栈, 动态链接, 方法出口等信息. 方法的执行就对应着栈帧在虚拟机栈中入栈和出栈的过程;
栈里面存放着各种基本数据类型和对象的引用(-Xss) ;-Xss 参数是用来调整 JAVA 虚拟机栈的. 一个线程调用多个方法, 只会有一个栈. 栈的缺省大小为 1M
3, 本地方法栈: 本地方法栈保存的是 native 方法的信息, 当一个 JVM 创建的线程调用 native 方法后, JVM 不再为其在虚拟机栈中创建栈帧, JVM 只是简单地动态链接并直接调用 native 方法;
堆:
方法区 (运行时常量池): 也叫永久区(永久代), 用于存储已经被虚拟机加载的类信息, 常量("zdy","123" 等), 静态变量(static 变量) 等数据(-XX:PermSize;- XX:MaxPermSize;-XX:MetaspaceSize; - XX:MaxMetaspaceSize ),
在 JDK7 及之前用的是 - XX:PermSize;-XX:MaxPermSize; 在 JDK8 及之后用的是(元数据空间)-XX:MetaspaceSize;-XX:MaxMetaspaceSize
JAVA 堆: 与我们操作最为紧密的区域, 在代码中用 new 对象的时候, 操作的就是该区域. 几乎是所有的对象都在堆上分配, 与堆相关的命令是:(-Xms;-Xmx;-Xmn;-XX:NewSize;-XX:MaxNewSize)
-Xms; 堆的最小值
-Xmx; 堆的最大值
-Xmn; 新生代的大小
-XX:NewSize; 新生代的最小值
-XX:MaxNewSize; 新生代的最大值
运行时常量池: 严格来说是方法区的一部分, JDK8 及之后运行时常量池放到了堆里面. JDK8 之后提出了元数据空间的概念, 这个方法区就消失了, 方法区从运行时数据区挪到了虚拟机本身管理之外, 只受制于物理内存的大小, 不再受制于虚拟机的管理内存大小. 同时运行时常量池也挪到了方法区. 元空间不是直接内存, 直接内存主要用于 IO 通信.
不同 JDK 版本之间运行时数据区也是有所不同的.
如 JDK6 的时候, 常量池是放在方法区中的
在 JDK7 的时候, 运行时常量池在对中
JDK8 及之后运行时常量池放到了堆里面
栈和堆对比分析 :
栈的特点:
1. 以栈帧的方式存储方法调用的过程, 并存储方法调用过程中基本数据类型的变量 (int,short,long,byte,float,double,boolean,char 等) 以及对象的引用变量,
2. 其内存分配在栈上, 变量出了作用域就会自动释放;
3. 栈内存归属于单个线程, 每个线程都会有一个栈内存, 其存储的变量只能在其所属线程中可见, 即栈内存可以理解成线程的私有内存.
栈的内存要远远小于堆内存, 栈的深度是有限制的, 可能发生 StackOverFlowError 问题
堆的特点:
1. 堆内存用来存储 Java 中的对象. 无论是成员变量, 局部变量, 还是类变量, 它们指向的对象都存储在堆内存中
2. 堆内存中的对象对所有线程可见. 堆内存中的对象可以被所有线程访问
来源: https://www.cnblogs.com/cheng21553516/p/11219856.html