1、内存模型
JVM 把内存分为了5个大的区域
程序计数器 | 线程私有 很小的一块区域 存放当前正在执行的字节码指令 唯一一块不会抛出任何异常的区域 |
java 虚拟机栈 | 线程私有 会抛出 OOM 异常 和 StackOverflowError 存储了方法执行时相关信息(栈帧) |
本地方法栈 | 线程私有 会抛出 OOM 异常 和 StackOverflowError 存储本地方法(也就是 native 修饰的函数 )调用相关信息 和 java 虚拟机栈统称 栈 |
方法区 | 线程共有 会有并发问题 会抛出 OOM 异常 存储的是每个class的信息 包括,类名,属性名,函数名等 函数的代码,和 运行时常量池 |
堆 | 线程共有 并发问题主要发生在这里 最大的一块内存区域,这一个区域又被分为了几个小的区域 年轻代:老年代,大小比例默认为 1:2 新 new 出来的对象基本都在 年轻代(大对象会直接进入老年代),新生代的对象大部分都是朝生夕死,经过多伦(默认 15 ) moiner gc 依然存货的对象会进入老年代 年轻代 GC 一般采用 标记复制算法,存活的对象都复制到 survivor 区域。 老年代的对象存活率比较高,这里发生的 GC 叫 Full GC 一般采用 CMS 算法(标记整理算法)或者 G1 算法(jdk 1.9 后默认的) |
jvm 标记一个对象是否是垃圾的方法:
1、引用计数法 - 无法解决循环引用问题
2、对象可达性分析 - 从根对象搜索,无法到达的对象未垃圾对象,需要被回收 - 三色标记法就是该算法的实践
垃圾回收
年轻代 - 标记复制算法
年轻代按照 8(eden):1(survivor0):1(survivor1) 被分为三块区域
初始状态 survivor 2个区域都为空,经过第一轮GC后会吧 存活对象复制进 survivor0 区域,在清空 eden 区域,当 survivor0 区域满了后会复制进 survivor1 区域survivor1 区域满了后会进入 老年代,并且 survivor0 和 survivor1 会始终保持一个区域为空,
老年代 - 标记整理算法(CMS 算法)
会分为几个步骤
1、初始标记
2、并发标记
3、重新标记
4、并发处理
对象在标记过程中,根据标记情况,分成三类:
- 白色对象,表示自身未被标记;
- 灰色对象,表示自身被标记,但内部引用未被处理;
- 黑色对象,表示自身被标记,内部引用都被处理;
更多 JAVA 相关问题关注小程序,如果对你有用帮忙点下广告,谢谢!!