JVM 内存管理
date: 2020-10-29 16:30:00
updated: 2020-10-29 17:10:00
JVM 内存管理
1. 堆和栈
JVM内存划分:
- 寄存器(程序计数器PC拿到指令地址,放入指令寄存器IR中,cpu执行指令)
- 本地方法区
- 方法区
- 栈内存(stack)
- 由编译器自动分配,存放函数的参数值,局部变量的值(定义在方法中的都是局部变量,方法外的是全局变量,for循环内部也是局部变量)
- 先加载函数才能进行局部变量的定义,所以方法先进栈,再定义变量,变量离开作用域后释放,生命周期都很短
- 堆内存(heap,不是数据结构中的堆)
- 由程序猿分配释放,如果程序猿不释放,程序结束时由GC回收
- 存储的是数组和对象,凡是new的都在堆中,实体(对象)里面封装了多个数据,一个数据消失,实体不会消失,还可以用,所以堆不会随时释放,会由GC不定时回收
int[] arr = new int[3];
主函数进栈 -> 在栈中定义一个 arr 变量 -> 在堆里通过new开辟一个空间,这个空间会产生一个地址,这个地址下的所有所有会进行初始化 -> 把内存的地址赋值给 arr
int[] arr = null; arr不做任何指向,null的作用就是取消引用数据类型的指向
1.1 堆
堆又分为
- 新生代
- 新生代又被进一步划分为Eden和Survivor区,最后Survivor由FromSpace和ToSpace组成
- 新建的对象都是由新生代分配内存
- 新生代大小可以由-Xmn来控制,也可以用-XX:SurvivorRatio来控制Eden和Survivor的比例
- 老年代
- 用于存放新生代中经过多次垃圾回收仍然存活的对象
1.2 栈
每个线程执行每个方法的时候都会在栈中申请一个栈帧,每个栈帧包括局部变量区和操作数栈,用于存放此次方法调用过程中的临时变量、参数和中间结果
2. GC
- 新生代GC
新生代通常存活时间较短,因此基于复制算法来进行回收,所谓复制算法就是扫描出存活的对象,并复制到一块新的完全未使用的空间中
新生代满了后,会把对象转移到旧生代,然后清空继续装载,当旧生代也满了后,就会报outofmemory的异常 - 老年代GC
老年代对象存活的时间比较长,比较稳定。因此采用标记(Mark)算法来进行回收,所谓标记就是扫描出存活的对象,然后再进行回收未被标记的对象,回收后对用空出的空间要么进行合并,要么标记出来便于下次进行分配,总之就是要减少内存碎片带来的效率损耗