1. JVM概述1.1什么是JVM JVM (javavirualmachine )? 也就是说,java虚拟机被理解为介于java编译器和操作系统之间的虚拟处理器,它既是java的核心,也是java的基础,而且可以运行java的字节码文件。
1.2 JVM原理概述java源文件编译生成字节码文件,类加载器将生成的字节码文件加载到JVM存储器中。 然后,JVM将字节码文件内的指令解释为JVM在各个平台上能够识别的机器码,最终在各个平台上执行机器码。
因此,可以看出系统执行java代码,实际上最终执行的是java代码经过一系列处理而生成的机器码。
1.3 JDK、JRE和JVM之间的联系人JDK:Java开发工具包,即Java开发工具包。
JRE:Java运行时环境,即Java执行环境。
JVM:Java虚拟机,即Java虚拟机。
当前的JDK通常附带JRE,但这三者之间存在包含关系,因为JRE包含JVM。 JDK包含JRE,JRE包含JVM。
2. JVM体系结构
从代码的执行过程来看,JVM主要做加载和执行两个工作,本文侧重于对执行的介绍。
加载:将. class文件加载到JVM内存中。
执行:执行发动机要做的事情,最终生产机器码。
2.1类加载器类加载器的作用是将. class文件加载到JVM的内存中。 与类加载机制、类加载器分类、父母委托模型等相关,但在此不再赘述。
2.2运行时数据区JVM的内存是指运行时数据区,主要包括以下五大部分:
堆方法区虚拟机堆栈本地方法在堆栈程序计数器中,堆和方法区属于共享内存区,是公共的; 虚拟机堆栈、本地方法堆栈和程序计数器是专用的,每个线程都有专用虚拟机堆栈、本地方法堆栈和程序计数器的存储空间。
在线程维中,一个线程在JVM中占用的内存应该由公用内存的专用内存组成。
堆
用于存储由数组和new关键字创建的对象的堆。 此内存由所有线程共享。
堆也是产生垃圾回收(GC )的生产场所,所有死亡对象占用的内存通过垃圾回收被释放。 堆毕竟也是有限的内存资源,不是无限的。
方法区
方法区域包含类中的类信息、静态变量、final类型常量、Field信息和方法信息。 此区域也由所有线程共享。
通常被称为常量池的实际上也位于方法区域中,从方法区域分配内存区域,并存储固定的常量信息。
虚拟机栈
虚拟机堆栈也称为堆栈、java堆栈和线程堆栈,是线程的专用。 每次创建线程时,都会创建自己的虚拟机堆栈,其中包含当前线程的基本类型变量。
本地方法栈
本地方法堆栈存储用native关键字标记的方法,正如其名称所示。 这些方法称为本机方法,是用非java语言(可能是c或c )编写的。
在前面的JVM体系结构图中,与本地方法接口交互的是本地方法堆栈。
程序计数器
一个程序计数器,用于记录当前线程执行的字节码指令的地址和行号。 理解为用于记录位置信息即可。
2.3引擎运行
执行引擎的主要组成部分有三个,分别是解释器、JIT编译器和垃圾收集器。
执行引擎角色:执行字节码文件或本地方法。
解释器读取字节码指令,并依次执行。
JIT编译器即时编译器、提高程序运行速度和性能并不是必须的。
垃圾收集器收集并删除堆内存中的死(未引用)对象以释放内存资源。
3 .如何确定JVM垃圾回收3.1对象是否存在有两种方法可以确定一个对象是否存在。 一个是引用计数,另一个是可达性分析。
引用计数法
每个对象都有一个引用计数器,一旦引用该对象,计数器就会加1。 如果引用无效,计数器将减去1。 如果计数器为0,则意味着此对象已死亡,可以回收。
可达性分析法
从称为“GC Root”的对象开始搜索。 搜索通过的路径称为参照链,表示如果参照链未连接到某个对象,则该对象将被视为不可到达、死亡,并可重用。 可以理解为数据结构中的“连通图”。
引用计数法的缺点是循环引用问题很难解决。
在可达性分析法中,可以用作GC Roots的对象包括虚拟机堆栈中引用的对象、本地方法堆栈中本地方法引用的对象、方法区域中静态属性引用的对象、常量引用的对象
3.2引用无论是引用计数法还是可达性分析法都与引用有关。 引用主要分为四类:
强参照软参照弱参照伪参照(1)强参照最常用,缺省情况下,所有对象都采用强参照。
)软引用可用于实现缓存,适用于缓存场景。 垃圾收集器仅在内存容量不足时回收它们
使用了软引用的对象,释放内存。(3)弱引用,当一个对象只有弱引用时,无论内存空间是否足够,垃圾收集器都会回收该对象。
(4)虚引用,主要用来跟踪对象被垃圾回收的活动,判断对象是否被垃圾回收。
3.3 主要进行垃圾回收的区域进行垃圾针对的目标是对象,而对象是存在于堆中的,所以进行垃圾回收的区域主要是堆。
堆内存,由两个部分组成,虚幻的路灯代(Young Generation)和老年代(Old Generation)。
(1)minorGC(又称youngGC):指在虚幻的路灯代中进行垃圾回收,清理死亡的对象,释放内存空间。
(2)oldGC:指在老年代中做垃圾回收,清理死亡的对象,释放内存空间。
(3)fullGC(通常认为majorGC也等价于fullGC):指对整个堆内存(包括虚幻的路灯代和老年代)和方法区进行垃圾回收。
3.4 垃圾回收触发条件(1)minorGC触发条件:当年轻代中的Eden区满时,会触发minorGC。minorGC进行的比较频繁。
(2)oldGC触发条件:当老年代满时,会触发oldGC。
(3)fullGC(majorGC)触发条件大致有以下五个:
调用System.gc方法老年代空间不足方法区空间不足通过 Minor GC 后进入老年代的空间大于老年代的可用内存空间由Eden区、Survivor From区向Survivor To区复制时,To 区可用内存小于对象大小,因此把该对象转存到老年代,然而老年代的可用内存也小于该对象大小 4. 垃圾收集算法
垃圾收集算法有四种,分别是:
(1)标记-清除算法:分两个阶段,一个“标记”阶段,一个是“清除”阶段。首先标记出所有不需要回收的对象,然后再清除所有没有被标记的对象,回收内存空间。
这个算法有两个不足之处:一个是效率问题,标记和清除的效率都不高;另一个是空间问题,标记清除后会产生大量不连续的内存碎片。
(2)复制算法:把内存分为大小相同的两块,每次使用其中的一块。当⼀块内存使⽤完后,便将内存中还存活的对象复制到另⼀块内存中去,然后再把原先使用过的内存空间⼀次性清理干净。这样就使得每次的内存回收都是对内存区间的⼀半进行回收,而且不会存在不连续的内存碎片问题。
复制算法,解决了内存碎片问题,但内存利用率不高。
(3)标记-整理算法:也分两个阶段,第一个阶段类似标记-清除算法的第一阶段,先标记出所有不需要回收的对象;第二个阶段是整理,将所有被标记的对象都移动到同一端,然后再一次性清理掉端边界以外的内存区域。
标记-整理算法,同样解决了内存碎片化问题。
(4)分代收集算法:因为堆分为虚幻的路灯代和老年代两个部分,且每个部分都有各自的特点,所以分代收集算法根据它们各自的特点,选择不同的垃圾收集算法进行回收。
虚幻的路灯代:每次进行垃圾回收时都会有大量对象死去,少量存活,所以使用复制算法老年代:对象存活率高、没有额外空间进行分配,可以用标记—清除或标记—整理算法分代收集算法,是目前虚拟机普遍采用的垃圾收集算法,应用最多。
5. 常见垃圾收集器
常见的垃圾收集器有七种,分别是:
(1)Serial收集器:单线程收集器,串行化执行,简单高效;虚幻的路灯代采用复制算法,老年代采用标记-整理算法。
(2)Serial Old收集器:Serial收集器的老年代版本,主要采用标记-整理算法收集垃圾;可作为CMS收集器的后备方案。
(3)ParNew收集器:是Serial收集器的多线程版本,除了采用多线程收集垃圾外,其余参数和Serial收集器一样。同样的,虚幻的路灯代采用复制算法,老年代采用标记-整理算法。
(4)Parallel Scavenge收集器:多线程收集器,虚幻的路灯代采用复制算法,老年代采用标记-整理算法。与ParNew收集器相比,它更关注吞吐量(CPU中用于运行用户代码的时间/CPU总消耗时间),目标是达到一个可控的吞吐量,高效利用CPU时间。这是JDK1.8默认的收集器。
(5)Parallel Old收集器:Parallel Scavenge收集器的老年代版本,多线程,使用标记-整理算法。
(6)CMS收集器:英文全称Concurrent Mark Sweep,一种以获取最短回收停顿时间为目标的收集器,非常适合应用在注重用户体验的场景。
基于标记-清除算法,整个过程分四个步骤:
初始标记并发标记重新标记并发清除。优点:并发收集、低停顿。
缺点:对CPU资源敏感、无法处理浮动垃圾、因使用标记-清除算法产生大量无法处理的内存碎片。
(7)G1收集器:一款面向服务器的垃圾收集器,适用于配备有多核处理器及大容量内存的机器。
G1收集器特点:
并行与并发:利用了多个CPU多线程的优势分代收集:G1可以不需要其它GC收集器的配合就能独立管理整个堆,但保留了分代的概念空间整合:整体采用标记-整理算法,局部采用复制算法,不会产生碎片问题可预测的停顿:能让使用者明确指定一个时间片段内,消耗在垃圾收集上的时间不超过指定时间范围内G1收集器的运作分为以下几个步骤:
初始标记并发标记最终标记筛选回收