JVM是一种规范。JVM的跨平台性。JVM的语言无关性。
常见的JVM实现:Hotspot(Oracle公司)、Zing(C4垃圾回收算法)、毕昇(华为公司)
运行时数据区域分为线程共享区和线程私有区
线程共享区包含:方法区、堆。运行时常量池在方法区中
线程私有区包含:虚拟机栈、本地方法栈、程序计数器
方法区(存储类加载Class类、静态常量(基本数据类型)、常量(基本数据类型)、static静态代码块、运行时常量池)
成员变量指向(对象)在类加载的时候不会执行,运行时成员变量会存储在堆中,
堆(存储对象实例)
栈(存储局部变量、引用对象)先进后出
运行时数据区外还存在一个直接内存,又称为堆外内存。
虚拟机栈存放的方法的栈帧
虚拟机栈存储当前线程运行java方法所需的数据、指令、返回地址
-Xss 256K 限制大小
栈溢出一般是出现了死递归
栈帧包含:局部变量表、操作数栈(不会被回收,会被复用)、动态连接、完成出口(返回地址)
程序计数器记录的是字节码运行的行号,记录的是偏移量
Java中直接内存(堆外内存)有哪些:使用Unsafe操作本地内存、JNI或者JNA程序操作了本地内存
//直接分配128的直接内存
ByteBuffer buffer=ByteBuffer.allocateDiret(128*1024*1024);
直接内存的申请绕过了JVM的垃圾回收。好处是速度会稍微快点。缺点就是容易忘记回收造成内存泄漏。多线程申请内存会造成覆盖。
JVM编译:
.java文件经过javac指令编译成.class文件
类加载把.class文件加载到方法区交由JVM执行引擎去执行
jvm把字节码翻译成机器码
分为老生代、新生代(Eden、From、To)。老生代存放的是经过多次GC垃圾回收没有回收掉的对象。
新生代经过15次GC后会晋升为老生代。对象经历一次垃圾回收,没有被回收掉。age+1。age达到15 晋级老生代。底层记录对象的年龄是用4位二进制,最大值位1111也就是15。
JHSDB工具查看内存。
JVM哪些区域会发生内存溢出:堆、虚拟机栈、方法区
JVM中对象的创建过程
类加载----》
检查加载(JVM遇到一条字节码new指令)-----》
分配内存(划分内存的方式:指针碰撞、空闲列表。解决并发安全:CAS加失败重试、本地线程分配缓冲)----》
内存空间初始化(“零”值)—》
设置(对象头)----》
对象初始化(构造方法)
使用指针碰撞内存必须是规整的。如果内存不规整,或者存在内存碎片就需要使用空闲列表方式。
CAS:是CPU的一个指令。多线程使用时使用CAS比较和交换。
本地线程分配缓冲:预先给每个线程划分一块内存区域(java8以后使用此种方式,禁止以后使用的就是CAS的方式)
对象分为:
1、对象头(Mark Word存储对象自身的运行时数据(哈希码、GC分代年龄、锁状态标识、线程持有的锁、偏向线程ID、偏向时间戳)、类型指针、若为对象数组,还应有记录数组长度的数据)
2、实例数据
3、对象填充(非必须)
对象的访问定位:使用句柄或者直接指针的方式。目前主流的JVM使用的是直接指针方式
垃圾回收GC,需要判断对象的存货
引用计数算法 没法解决循环引用的关系
可达性分析(根可达)
经过判断对象存活后还会有一个Finalize 缓冲期。Finalize是类的自我拯救。因为是另起了一个线程,所有优先级比较低 ,不推荐使用。
从根找可达 根有 静态变量----》线程栈变量-----》常量池----》JNI(指针)—》内部引用(class对象、异常对象Exception。类加载器)—》同步锁----》内部对象----》临时对象(跨代引用)
class new 出的所有对象都要回收
对应的类加载器 也要回收
类 Java.lang.class对象,
任何地方没有引用,并且无法通过反射调用这个类的方法
参数控制
几乎所有的对象都在堆中进行分配,对象触发逃逸分析会把对象会分配到栈中(java 10000次)
对象优先在Eden分配 (常用)
空间分配担保
大对象直接进入老年代
长期存活的对象进入老年代 (常用)
动态对象年龄判定
逃逸分析+触发JIT(热点数据) 对象会分配到栈中
本地线程分配缓冲
新生代内存分配规则:Eden:form:to=8:1:1
特点:实现简单、运行高效。没有内存碎片。空间利用率只有一半
根据可达性分析标记引用的对象,然后清除没有引用的对象
特点:位置不连续,产生碎片。可以不暂停。
根据可达性分析标记引用的对象,先标记,后整理内存空间。 最后整体清理
特点:没有内存碎片。指针需要移动。
Serial 回收新生代 复制算法 回收器类型属于单线程
Serical Old 回收老年代 标记整理算法 回收器类型属于单线程
Paraller Scavenge 回收新生代 复制算法 回收器类型属于多线程并行垃圾回收器
Paraller Old 回收老年代 标记整理算法 回收器类型属于多线程并行垃圾回收器
PaeNew 回收新生代 复制算法 回收器类型属于多线程并行垃圾回收器
CMS 回收老年代 标记清除算法 回收器类型属于并发的多线程回收器
G1 跨新生代和老年代 标记整理+化整为零算法 回收器类型属于并发的多线程回收器
CMS的标记清除算法的过程减少了暂停卡顿:初始标记 并发标记 重新标记 并发清除
CMS中的问题:CPU敏感 浮动垃圾 内存碎片
面试题
常量池(方法区):
Class常量池(静态常量池)
运行时常量池
字符串常量池