1 JVM 内存划分
2 分区
JVM 内存区域次要分为线程公有区域【程序计数器、虚拟机栈、本地办法区】、线程共享区域【JAVA 堆、办法区】、间接内存。
2.1 程序计数器
一块较小的内存空间, 是以后线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为“线程公有”的内存。
正在执行 java 办法的话,计数器记录的是虚拟机字节码指令的地址(以后指令的地址)。如果还是 Native 办法,则为空。
这个内存区域是惟一一个在虚拟机中没有规定任何 OutOfMemoryError 状况的区域。
2.2 虚拟机栈
是形容 java 办法执行的内存模型,每个办法在执行的同时都会创立一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动静链接、
办法进口等信息。每一个办法从调用直至执行实现的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
2.3 本地办法区
本地办法区和 Java Stack 作用相似, 区别是虚拟机栈为执行 Java 办法服务, 而本地办法栈则为 Native 办法服务,
如果一个 VM 实现应用 C-linkage 模型来反对 Native 调用, 那么该栈将会是一个 C 栈,但 HotSpot VM 间接就把本地办法栈和虚拟机栈合二为一。
2.4 堆 - 运行时数据区
是被线程共享的一块内存区域,创立的对象和数组都保留在 Java 堆内存中,也是垃圾收集器进行垃圾收集的最重要的内存区域。因为古代 VM 采纳分代收集算法, 因而 Java 堆从 GC 的角度还能够细分为: 新生代 (Eden 区、From Survivor(S0) 区和 To Survivor (S1) 区)和老年代。
2.5 办法区
即咱们常说的永恒代 (Permanent Generation), 用于存储被 JVM 加载的类信息、常量、动态变量、即时编译器编译后的代码等数据. HotSpot VM 把 GC 分代收集扩大至办法区, 即应用 Java 堆的永恒代来实现办法区, 这样 HotSpot 的垃圾收集器就能够像治理 Java 堆一样治理这部分内存, 而不用为办法区开发专门的内存管理器(永恒带的内存回收的次要指标是针对常量池的回收和类型的卸载, 因而收益个别很小)。
运行时常量池(Runtime Constant Pool)是办法区的一部分。Class 文件中除了有类的版
本、字段、办法、接口等形容等信息外,还有一项信息是常量池。
1.7 之后曾经移除了永恒代,而是元空间
元空间的实质和永恒代相似,都是对 JVM 标准中办法区的实现。不过元空间与永恒代之间最大的区别在于:元空间并不在虚拟机中,而是应用本地内存。因而,默认状况下,元空间的大小仅受本地内存限度,但能够通过以下参数来指定元空间的大小:
- -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时 GC 会对该值进行调整:如果开释了大量的空间,就适当升高该值;如果开释了很少的空间,那么在不超过 MaxMetaspaceSize 时,适当进步该值。
- -XX:MaxMetaspaceSize,最大空间,默认是没有限度的。
- -XX:MinMetaspaceFreeRatio,在 GC 之后,最小的 Metaspace 残余空间容量的百分比,缩小为调配空间所导致的垃圾收集
- -XX:MaxMetaspaceFreeRatio,在 GC 之后,最大的 Metaspace 残余空间容量的百分比,缩小为开释空间所导致的垃圾收集
3 JVM 根底
3.1 对象的创立
对于内存不规整的状况,容易产生指针碰撞
对于内存规整的状况,容易产生闲暇列表
3.2 对象内存布局
- 对象头(Mark Word):存储对象本身的运行时数据,如哈希码,GC 分带年龄,锁状态标记,线程持有的锁,偏差线程 ID,偏差工夫戳。
数据长度在 32 位和 64 位虚拟机中别离为 32bit 和 64bit。另外一部分是类型指针,即对象指向它的类元数据的指针。 - 实例数据:真正的无效信息,定义的各种类型字段的内容,父类继承的也会记录。
- 对齐填充:不是必然存在的,HotSpot 要求对象起始地址(对象大小)必须是 8 的倍数,对象头局部刚好是 1 倍或 2 倍,因而当实例数据局部没对齐时,就须要主动填充来补齐。
3.3 对象是否存活
- 援用计数法:给对象增加一个援用计数器,有一个援用加 1,援用生效时减 1,计数器为 0 则对象不再被应用。毛病无奈解决循环援用的问题。
- 可达性分析法:通过一系列的“GC Roots”的对象作为起始点,往下搜寻,当一个对象达到 GC Roots 没有任何援用链相连,则对象不可用,可回收。
GC Roots:
- 虚拟机栈(栈针中的本地变量表)中援用的对象
- 办法区中的类动态属性援用的对象
- 办法区中常量援用的对象
- 本地办法栈中 JNI(Native 办法)援用的对象
3.4 对象的生或死
在可达性剖析算法中的不可达对象,也不是非死不可,宣告一个对象的死亡,至多要通过两次标记过程,没有援用链的对象,
会进行第一次标记并且筛选,筛选条件是此对象是否有必要执行 finalize()办法。当对象没有笼罩 finalize()办法或者虚拟机曾经执行过,
则视为没必要执行。finalize()只会被零碎调用一次。对象有可能在 finalize 办法中被援救。
本文由 mdnice 多平台公布