是运行所有Java程序的抽象计算机,运行所有Java程序的抽象计算机,是Java语言的运行环境,它是Java 最具吸引力的特性之一。
虚拟机jvm就是一个操作系统中的进程实例。
堆
所有对象都在这里分配内存,是垃圾回收的主要区域。
方法区
用于存放加载的类信息、常量、静态变量、即时编译后的代码等数据。
运行时常量池
Class文件的常量池,会在类加载后被放入这个区域
jJava虚拟机栈
用于存放局部变量、操作数栈、常量池引用等信息。
本地方法区
本地⽅法⼀般是⽤其它语⾔(C、C++ 或汇编语⾔等)编写的,并且被编译为基于本机硬件和操作系统 的程序,对待这些⽅法需要特别处理。
程序计数器
记录正在执⾏的虚拟机字节码指令的地址
注:java虚拟机栈、本地方法区、程序计数器为线程私有。
垃圾收集主要是在堆和方法区进行
方法区的回收主要是对常量池的回收和类的卸载。
当一个对象被回收时,如果需要执行finalize()方法,那么对象会被重新引用,从而实现复活,再第二次回收的时候就不会再被复活。
以 GC Roots 为起始点进⾏搜索,可达的对象都是存活的,不可达的对象可被回收。
GC Roots分为:
对象被引用时,引用计数器加1,当对象引用失效后,引用计数器减1。当引用计数器的值为0的时候,对象就可被回收。
缺点:互相引用的对象不会被回收。
强引用
使用new的方式来创建强引用,强引用的对象不会被回收。
软引用 (SoftReference)
通过SoftReference
类来创建,只用当内存不足的时候才会被回收。
弱引用 (WeakReference)
通过WeakReference、来创建,只能存活到下一次垃圾回收发生之前。
虚引用 (PhantomReference)
使用PhantomReference
类来创建,一个对象是否存在虚引用对其生存时间不影响。
描述: 首先标记需要回收的对象,在标记完成后统一回收所有被标记的对象,标记方法使用 根搜索算法。
缺点:1、标记和清除的效率都不高 2、会产生大量内存碎片,导致大对象无法分配内存。
描述:标记方法同上,但后续将所有存活的对象移动到内存的一端,然后清除掉端外的对象。
缺点:1、需要移动大量对象,处理效率比较低。
优点:1、不会产生内存碎片。
描述:将内存分为一块Eden空间和两块较小的Survivor空间,每次使用eden空间和一块survivor空间,在回收时将eden和其survivor空间存活的对象复制到另一块survivor空间,最后清除eden和其survivor空间。
缺点: 将内存一分为二,导致内存使用率大大降低
优点:有效避免内存碎片
描述:内存分为新生代和老年代,在新生代采用复制算法,在老年代采用标记-清除和标记-整理算法。
Serial 收集器 : 它是单线程的收集器,只会使⽤⼀个线程进⾏垃圾收集⼯作。
ParNew 收集器:它是 Serial 收集器的多线程版本。
Parallel Scavenge 收集器:其它收集器⽬标是尽可能缩短垃圾收集时⽤户线程的停顿时间,⽽它的⽬标是达到⼀个可控制的吞吐 量,因此它被称为“吞吐量优先”收集器。这⾥的吞吐量指 CPU ⽤于运⾏⽤户程序的时间占总时间的⽐ 值。
Serial Old 收集器:是 Serial 收集器的⽼年代版本,
Parallel Old 收集器:是 Parallel Scavenge 收集器的⽼年代版本。
CMS收集器: CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法。通过增量标记来解决漏标。
G1收集器:对于堆内存不分老年代和新生代。划分为一个一个小内存块,叫做region。
STW: Stop-The-World 垃圾回收算法执行过程中,需要将jvm内存冻结的一种状态。
三色标记: 是一种逻辑上的抽象,将每个内存对象标记分为3个颜色: 黑色表示自己和成员变量都已经标记完毕。 灰色:自己标记完毕了,但成员变量还没有完全标记。白色:自己未标记
Minor GC:回收新⽣代,因为新⽣代对象存活时间很短,因此 Minor GC 会频繁执⾏,执⾏的速度 ⼀般也会⽐较快
触发条件: 对于 Minor GC,其触发条件⾮常简单,当 Eden 空间满时,就将触发⼀次 Minor GC。
回收⽼年代和新⽣代,⽼年代对象其存活时间⻓,因此 Full GC 很少执⾏,执⾏速度会⽐ Minor GC 慢很多
触发条件:
只是建议虚拟机执⾏ Full GC,但是虚拟机不⼀定真正去执⾏。不建议使⽤这种⽅式,⽽是让虚拟机管 理内存。
⽼年代空间不⾜的常⻅场景为前⽂所讲的⼤对象直接进⼊⽼年代、⻓期存活的对象进⼊⽼年代等。
使⽤复制算法的 Minor GC 需要⽼年代的内存空间作担保,如果担保失败会执⾏⼀次 Full GC。
在 JDK 1.7 及以前,HotSpot 虚拟机中的⽅法区是⽤永久代实现的,永久代中存放的为⼀些 Class 的信 息、常量、静态变量等数据。
执⾏ CMS GC 的过程中同时有对象要放⼊⽼年代,⽽此时⽼年代空间不⾜(可能是 GC 过程中浮动垃 圾过多导致暂时性的空间不⾜),便会报 Concurrent Mode Failure 错误,并触发 Full GC。
对象优先在 Eden 分配
⼤多数情况下,对象在新⽣代 Eden 上分配,当 Eden 空间不够时,发起 Minor GC。
⼤对象直接进⼊⽼年代
⼤对象是指需要连续内存空间的对象,最典型的⼤对象是那种很⻓的字符串以及数组。(-XX:PretenureSizeThreshold,⼤于此值的对象直接在⽼年代分配)
⻓期存活的对象进⼊⽼年代
为对象定义年龄计数器,对象在 Eden 出⽣并经过 Minor GC 依然存活,将移动到 Survivor 中,年龄就 增加 1 岁,增加到⼀定年龄则移动到⽼年代中。(-XX:MaxTenuringThreshold ⽤来定义年龄的阈值。)
动态对象年龄判定
如果在 Survivor 中相同年龄所有对象⼤⼩的总和⼤于 Survivor 空间的⼀半,则年龄⼤于或等于该年龄的对象可以直接进 ⼊⽼年代,⽆需等到 MaxTenuringThreshold 中要求的年龄。
空间分配担保
类是在运⾏期间第⼀次使⽤时动态加载的,⽽不是⼀次性加载所有类。因为如果⼀次性加载,那么会占 ⽤很多的内存。
每个类加载器都有缓存,查询类加载器时先依次去AppClassLoader缓存–>ExtClassLoader缓存–>BootsrapClassLoader缓存
双亲委派:向上委托查找,向下委托加载。 作用:包含Java的层的类不被应用程序覆盖。
类的⽣命周期
类加载器分类
启动类加载器(Bootstrap ClassLoader),使⽤ C++ 实现,是虚拟机⾃身的⼀部分
所有其它类的加载器,使⽤ Java 实现,独⽴于虚拟机,继承⾃抽象类 java.lang.ClassLoader。
扩展类加载器(Extension ClassLoader)、应⽤程序类加载器(Application ClassLoader)