jvm 主要由三个子系统构成: 类加载子系统, 运行时数据区(内存模型), 执行引擎
运行时数据区主要包括:
1. 本地方法栈: 登记 native 方法, 执行时加载本地方法库
2. 程序计数器: 就是一个指针, 用来存储指向下一条执行指令的地址, 也就是即将要执行的指令代码, 是一个非常小得空间, 可以忽略不计.
3.java 栈: java 线程执行方法的内存模型, 一个线程对应一个栈, 每个方法在执行时都会创建一个栈帧, 用于存储局部变量表(引用), 操作数栈, 动态链接, 方法出口等信息, 不存在垃圾回收问题, 生命周期和线程一致, 线程结束该栈就释放. 可以通过 - Xss 来设置栈空间.
4. 方法区: 类的所有字段和方法字节码, 以及一些特殊的方法, 构造函数, 接口定义, 所有定义的方法的信息都存放在这. 此外还包括静态变量, 常量, 运行时常量池
5.java 堆: 虚拟机启动时创建, 用于存放对象实例, 几乎所有的对象都在堆上面分配内存, 当对象无法在该空间申请到内存就会抛出 OutMemoryError 异常, 同时也是垃圾回收器主要管理的区域, 可以通过 - Xmx/Xms 来设置最大 / 最小堆
其中 1.2.3 都是线程私有, 4.5 线程共享
线程私有 java 栈图解:
java 堆详解:
新生代: 类诞生, 成长, 消亡的区域, 一个类在这里产生, 应用, 最后被垃圾回收器收集, 结束生命.
新生代分为两部分: 伊甸园区 (Eden space: 亚当, 夏娃造人, 这名字取得还是很有意义的) 和幸存者区 (Survivor pace) , 所有的类都是在伊甸园被 new 出来的. 幸存区有两个: 0 区(Survivor 0 space(From)) 和 1 区(Survivor 1 space(To)). 当伊甸园的空间用完时, 程序又需要创建对象, JVM 的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC), 将伊甸园区中的不再被其他对象所引用的对象进行销毁. 然后将伊甸园中的剩余对象移动到幸存 From. 若幸 From 也满了, 再对该区进行垃圾回收, 然后移动到 To.From 到 To 操作一次, 还存在 To 中的对象就相当于长了一岁, 默认是 15 岁, 如果到了 15 岁都还存在有引用, 那么就放入老年代, 可以用过 - XX:MaxTenuringThreshold 来设置这个年龄
老年代: 新生代经过多次 GC 仍然存活的对象移动到老年区. 若老年区也满了, 那么这个时候将产生 FullGC, 进行老年区的内存清理. 若老年区执行了 Full GC 之后发现依然无法进行对象的保存, 就会产生 OOM 异常 "OutOfMemoryError". 可以同过减少 FullGC 来提高 jvm 性能
永久代(元数据):jdk1.8 元数据区取代了永久代, 本质和永久代类似, 都是对 JVM 规范中方法区的实现, 区别在于元数据区并不在虚拟机中, 而是使用本地物理内存, 永久代在虚拟机中, 永久代逻辑结构上属于堆, 但是物理上不属于堆, 堆大小 = 新生代 + 老年代. 元数据区也有可能发生 OutOfMemory 异常.
Jdk1.6 及之前: 有永久代, 常量池在方法区
Jdk1.7: 有永久代, 但已经逐步 "去永久代", 常量池在堆
Jdk1.8 及之后: 无永久代, 常量池在元空间
元数据区的动态扩展, 默认 - XX:MetaspaceSize 值为 21MB 的高水位线. 一旦触及则 Full GC 将被触发并卸载没有用的类(类对应的类加载器不再存活), 然后高水位线将会重置. 新的高水位线的值取决于 GC 后释放的元空间. 如果释放的空间少, 这个高水位线则上升. 如果释放空间过多, 则高水位线下降.
来源: https://www.cnblogs.com/nijunyang/p/11037376.html