Java内存模型
堆
- 存储对象数据
- Eden区\新生代
- s0区(from)\新生代
- s1区(to)\新生代
- tenured区\老年代
栈
- 解决程序运行问题,即程序如何执行,或者说如何处理数据
- 存储局部变量,引用
主要有三部分组成:
- 局部变量表:用于函数报错的参数及局部变量
- 操作数栈:保存计算过程的中间结果,作为计算过程的变量临时空间。
- 帧数据区:异常处理表
方法区 (所有线程共享,永久区)
- 辅助堆栈的快永久区,解决堆栈信息的产生
- 存放类信息,常量信息,常量池信息,包括字符串字面量和数字常量。类过多可能会溢出。
GC
垃圾收集算法
引用计数法
- 思想:在被其他对象引用的时候引用计数器+1,引用失效时引用计数器-1。引用为0对象被回收。
- 算法弊端:无法处理循环引用的场景(递归对一个对象引用多次)
标记清除算法
- 思想:对没有引用的对象进行标记,GC进行的时候,若发现对象被标记则进行回收
- 算法弊端:由于对象的在内存中是随机分部,回收之后会产生内存碎片。
复制算法(新生代)对象存活时间短
- 思想:将内存分为2块,每次使用其中一块,GC进行时将含有引用的对象复制到未使用的那片内存区,然后垃圾收集器回收当前使用的内存区。如此反复的复制被引用的对象,清除无引用的对象被称为复制算法。(Java中的中S0内存区和S1内存区则是使用这种思想。)
标记压缩法(老年代)对象存活时间长
- 老年代比较稳定,对象存活时间长,标记压缩法在标记清除法上做了优化,将存活的对象压缩到内存一侧,然后清除无用对象。
分代算法:
分区算法(G1):
- 将内存区划分为多个小的分区,GC进行时,可以对每个小的分区回收,减少GC时的停顿时间。
对象如何进入老年代:
- 对象年龄达到一定大小则离开新生代进入老年代,对象年龄由GC次数决定,可以设置JVM参数(-XX:MaxTenuringThreshold)来设置年龄大小,大对象
TLAB:
- Thread Local Allocation Buffer(线程本地分配缓存器)(栈上分配)线程专用的内存区域,为了加速对象的分配产生的。一般不会太大,当大对象不能在TLAB上分配时,就分配到堆上。
创建对象内存分配过程:
- 栈上分配(若失败进入下一步,若成功结束流程)—》在TLAB上分配(若失败进入下一步,若成功结束流程)—》是否满足进入老年代(若失败进入下一步,若成功结束流程)—》Eden分配(结束)
垃圾回收器
串行垃圾回收器(单线程):SerialGC
并行垃圾回收器(多线程):
- ParNew(新生代),
- CMS(并发标记清除)回收器,当达到阈值进行回收内存,默认阈值为: 68%
- G1 分代+分区 思想