JVM 学习-内存管理
2 JVM的内存管理
所有的数据和程序都是在运行数据区存放,它包括以下几部分:
- Stack 栈
栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是 一个有关方法(Method)和运行期数据的数据集,当一个方法A被调用时就产生了一个栈帧 F1,并 被压入到栈中,A方法又调用了 B方法,于是产生栈帧 F2 也被压入栈,执行完毕后,先弹出 F2 栈帧,再弹出 F1 栈帧,遵循“先进后出”原则。
那栈帧中到底存在着什么数据呢?栈帧中主要保存3 类数据:本地变量(Local Variables), 包括输入参数和输出参数以及方法内的变量;栈操作(Operand Stack),记录出栈、入栈的操作; 栈帧数据(Frame Data),包括类文件、方法等等。光说比较枯燥,我们画个图来理解一下 Java 栈,如下图所示:
- Heap 堆内存
永久存储区是一个常驻内存区域,用于存放 JDK 自身所携带的 Class,Interface 的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭 JVM 才会释放此区域所占用的内存。
新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。新生区又分为两部分: 伊甸区(Eden space)和幸存者区(Survivor pace) ,所有的类都是在伊甸区被new出来的。幸存区有两个: 0区(Survivor 0 space)和1区(Survivor 1 space)。当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收,将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后将伊甸园中的剩余对象移动到幸存 0区。若幸存 0区也满了,再对该区进行垃圾回收,然后移动到 1 区。那如果1 区也满了呢?再移动到养老区。
养老区用于保存从新生区筛选出来的 JAVA 对象,一般池对象都在这个区域活跃。 三个区的示意图如下:
- Method Area 方法区
- PC Register 程序计数器
- Native Method Stack 本地方法栈
2 //静态类常量,
3 public final static String ClASS_CONST = "I'm a Const";
4 //私有实例变量
5 private int instanceVar=15;
6 public static void main(String[] args) {
7 //调用静态方法
8 runStaticMethod();
9 //调用非静态方法
10 JVMShowcase showcase=new JVMShowcase();
11 showcase.runNonStaticMethod(100);
12 }
13 //常规静态方法
14 public static String runStaticMethod(){
15 return ClASS_CONST;
16 }
17 //非静态方法
18 public int runNonStaticMethod(int parameter){
19 int methodVar=this.instanceVar * parameter;
20 return methodVar;
21 }
22 }
![](https://images.cnblogs.com/cnblogs_com/sundaweixy/JVM/20120221234702601.jpg)
Heap是空,Stack是空,因为还没有线程被执行。Class Loader通知Execution Enginer已经加 载完毕。
第 5 步,执行引擎执行 main 方法。执行引擎启动一个线程,开始执行 main 方法,在 main 执 行完毕前,方法区如下图所示:
在 Method Area加入了CLASS_CONST 常量,它是在第一次被访问时产生的。堆内存中有两个对象 object和 showcase对象,如下图所示:
为什么会有 Object对象呢?是因为它是JVMShowcase的父类,JVM是先初始化父类,然后再 初始化子类,甭管有多少个父类都初始化。在栈内存中有三个栈帧,如下图所示:
于此同时,还创建了一个程序计数器指向下一条要执行的语句。
第 6 步,释放内存。运行结束,JVM向操作系统发送消息,说“内存用完了,我还给你”,运行结束。