
绿色的为线程私有,橘色的为线程共有
负责将.class文件加载到内存中,并且将该文件中的数据结构转换为方法区中的数据结构,生成一个Class对象

Bootstrap ClassLoader类加载器。负责加载jdk自带的包。%JAVA_HOME%/lib/rt.jar%即JDK源码C++编写nullExtension ClassLoader。负责加载jdk扩展的包%JAVA_HOME/lib/ext/*.jar%AppClassLoader或SystemClassLOaderCLASSPATH路径下ClassLoader抽象类实现当应用类加载器获取到一个类加载的请求的时候,不会立即处理这个类加载请求,而是将这个请求委派给他的父加载器加载,如果这个父加载器不能够处理这个类加载请求,便将之传递给子加载器。一级一级传递指导可以加载该类的类加载器。
该机制又称「沙盒安全机制」。防止开发者对JDK加载做破坏

loadClass方法sun.misc.Launcher类
执行引擎负责执行解释命令,交给操作系统进行具体的执行
native方法指Java层面不能处理的操作,只能通过本地接口调用本地的函数库(C函数库)
一套调用函数库的接口
在加载native方法的时候,会将执行的C函数库的方法,放在这个栈区域执行
每个线程都有程序计数器,主要作用是存储代码指令,就类似于一个执行计划。
内部维护了多个指针,这些指针指向了方法区中的方法字节码。执行引擎从程序计数器中获取下一次要执行的指令。
由于空间很小,他是当前线程执行代码的一个行号指示器/
不会引发OOM
供各线程共享的运行时内存区域,存放了各个类的结构信息(一个Class对象),包括:字段,方法,构造方法,运行时常量池。
虽然JVM规范将方法区描述为堆的一个逻辑部分,但它却还有一个别名叫做Non-Heap(非堆),目的就是要和堆分开
主要有:永久代或者元空间。存在GC
元空间中由于直接使用物理内存的影响,所以默认的最大元空间大小为1/4物理内存大小
主要负责执行各种方法,是线程私有的,随线程的消亡而消亡,不存在垃圾回收的问题。八大数据类型和实例引用都是在函数的栈内存中分配内存的。
默认大小为512~1024K,通过-Xss1024k参数修改
栈FILO:先进后出
队列FIFO:先进先出
Local Variable。包括方法的形参和返回值Operand Stack。包括各种压栈和出栈操作Frame Data。就相当于一个个方法。在栈空间中,方法被称为栈帧栈中执行的单位是栈帧,栈帧就是一个个方法。
main方法压栈,成为一个栈帧256K~756K

默认初始大小为物理内存的1/64,默认最大大小为1/4。在实际生产中一般会将这两个值设置为相同,避免垃圾回收器执行完垃圾回收以后还需要进行空间的扩容计算,浪费资源。
堆外内存:内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机),这样做的结果就是能够在一定程度上减少垃圾回收对应用程序造成的影响。使用未公开的Unsafe和NIO包下ByteBuffer来创建堆外内存。
默认的堆外内存大小为,通过-XX:MaxDirectMemorySize=执行堆外内存的大小

「在逻辑上划分为三个区域:」
Young Generation Space。Eden SpaceSurvivor 0 SpaceSurvivor 1 SpaceTenure Generation SpacePermanent Space(方法区)「在物理层面划分为两个区域:」

「主要流程有三步:」
Eden满了以后出发一次轻GC(Minor GC),没有死亡的对象,年龄+1,存放到from区域Eden再次满了以后再次触发一次GC,没有死亡的对象放置于to区域,然后将from区域中没有死亡的对象全部置于to区域,年龄+1。之后每一次GC都会触发一次from和to的交换,「哪个区域是空的那个区域就是to」survivor区域满了以后,再次触发GC,当存在对象的年龄等于15的时候,就会将该对象移入老年区MaxTenuringThreshold通过这个参数设置当年龄为多少的时候移入Full GC,如果老年区无法再存放对象直接报OOM「注意:每一次GC都会给存活的对象的年龄+1」
和1.7相比,仅仅是将永久代更替为了「元空间」。元空间的存放内置是「物理内存」,而不是JVM中。
这样处理,可以使元空间的大小不再受虚拟机内存大小的影响,而是由系统当前可用的空间来控制。
新生区和老年区的大小比例为1:2,通过-XX:NewRatio=n设置新生代和老年代的比例,n代表老年区所占的比例。
Eden Space和Survivor Space之间的比例默认为8:1,通过-XX:SurvivorRatio设置伊甸区和幸存者区的比例
「逻辑层面分层:」
Young Generation SpaceEden SpaceSurvivor 0 SpaceSurvivor 1 SpaceTenure Generation Space「物理层面分层:」

参数 | 作用 |
|---|---|
-Xms | 设置初始堆大小,默认为物理内存的1/64 |
-Xmx | 设置最大堆大小,默认为物理内存的1/4 |
-XX:+PrintGCDetails | 输出详细的GC日志 |
「模拟OOM」
//设置最大堆内存为10m
//-Xms10m -Xmx10m -XX:+PrintGCDetails
下面我们具体分析一下GC的过程做了什么,GC日志怎么看
「名称:GC以前占用->GC之后占用(总共占用)」
//GC 分配失败
GC (Allocation Failure)
[PSYoungGen: 1585K->504K(2560K)] 1585K->664K(9728K), 0.0009663 secs] //[新生代,以前占用->线程占用(总共空闲)] 堆使用大小->堆现在大小(总大小)
[Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure)
[PSYoungGen: 0K->0K(2560K)]
[ParOldGen: 590K->573K(7168K)] 590K->573K(9728K),
[Metaspace: 3115K->3115K(1056768K)], 0.0049775 secs]
[Times: user=0.00 sys=0.00, real=0.01 secs] minor GC)发生在新生区的,很频繁major GC发生在老年代的垃圾收集动作,出现一次major GC经常会伴随至少一次的Minor GC主要思想:每存在一个对象引用就给这个对象加一,当这个对象的引用为零的时候,便触发垃圾回收。一般不使用
「缺点:」
主要思想:将对象直接拷贝一份,放置到其他区域
优点:不会产生内存碎片
缺点:占用空间比较大
使用场景:新生区的复制就是通过复制算法来执行的。当Minor Gc以后,就会幸存的对象复制一份放置到to区
主要思想:从引用根节点遍历所有的引用,标记出所有需要清理的对象,然后进行清除。「两步完成」
缺点:在进行垃圾回收的时候会打断整个代码的运行。会产生内存碎片
主要思想:和标记清除算法一样,最后添加了一个步骤整理,将整理内存碎片。「三步完成」
缺点:效率低,需要移动对象。
复制算法>标记清除法>标记整理法
复制算法=标记整理法>标记清除法
标记整理法=标记清除法>复制算法
通过场景使用不同的算法,来达到最优的目的
年轻代:因为其对象存活时间段,对象死亡率高,所以一般使用复制算法
老年代:区域大,存活率高,一般采用标记清除和标记整理的混合算法。
「老年代一般是由标记清除或者是标记清除与标记整理的混合实现。以hotspot中的CMS回收器为例,CMS是基于Mark-Sweep实现的,对于对像的回收效率很高,而对于碎片问题,CMS采用基于Mark-Compact算法的Serial Old回收器做为补偿措施:当内存回收不佳(碎片导致的Concurrent Mode Failure时),将采用Serial Old执行Full GC以达到对老年代内存的整理。」
上面我们提到标记清除算法的时候,提到了一个名词,「根节点引用」。那么什么叫做根节点引用呢?
根节点引用也称GCRoots,他是指垃圾回收算法进行对象遍历的根节点。即从这个对象开始往下遍历,标记需要进行回收的对象。
垃圾回收标记的过程就是:以GCRoots对象开始向下搜索,如果一个对象到GCRoots没有任何的引用链相连时,说明此对象不可用。
就是从GCRoots进行遍历,「可以被遍历到的就不是垃圾,没有被遍历到的就是垃圾,判定死亡」
可达性对象是指,在对象链路引用的顶层是一个GCRoot引用
不可达对象是指,在对象链路引用的顶层不是一个GCRoot引用

通俗解释:可达性对象就是对象有一个归属,这个归属有一个术语名称叫做GCRoot,不可达性对象就是这些对象没有归属。
native修饰的方法「说白了,就是所有暴露给开发者的引用」
垃圾回收器是基于GC算法实现的。
主要有四种垃圾回收器,不过具体有七种使用方式
单线程进行垃圾回收,此时其他的线程全部被暂停
通过-XX:+UseSerialGC
多线程进行垃圾回收,此时其他的线程全部被暂停
GC线程和用户线程同时运行
分区垃圾回收。物理上不区分新生区和养老区,将堆内存划分为1024个小的region,每一个占据的空间在2~32M,每一个region都可能是Eden Space、Survivor01 Space、Survivor02 Space和Old区。
整体使用了标记整理算法,局部使用了复制算法。通过复制算法将GC后的对象从一个region向另一个region迁移,至于造成了内存碎片问题,通过整体的标记整理算法,避免了内存碎片的诞生
在进行垃圾回收的时候直接对一个region进行回收,保存下来的对象通过复制算法复制到TO区或者Old区。
逻辑上堆有四个区,每一个区的大小不定,按需分配。分为Eden Space,Survivor01 Space,Old和Humongous。其中Humongous用来存放大对象,一般是连续存储,当由于连续region不足的时候,会触发Full GC清理周围的Region以存放大对象
「G1堆内存示意」

「G1垃圾回收」

「出现大对象,三个region不能存放,进行FullGC」

「执行流程」
GCRootsGCRoots的所有的对象,进行标记


Full GC
-XX:+UseG1GC 开启GC
-XX:G1HeapRegionSize=n : 设置G1区域的大小。值是2的幂,范围是1M到32M。目标是根据最小的Java堆大小划分出约2048个区域
-XX:MaxGCPauseMillis=n : 最大停顿时间,这是个软目标,JVM将尽可能(但不保证)停顿时间小于这个时间
-XX:InitiatingHeapOccupancyPercent=n 堆占用了多少的时候就触发GC,默认是45
-XX:ConcGCThreads=n 并发GC使用的线程数
-XX:G1ReservePercent=n 设置作为空闲空间的预留内存百分比,以降低目标空间溢出的风险,默认值是10%DefNew Default New Generation //串行垃圾回收器,新生代叫法
Tenured Old //串行垃圾回收器,老年代叫法
ParNew Parallel New Generation //新生代并行垃圾回收器,新生代叫法
PSYongGen Parallel Scavenge //新生代和老年代垃圾回收器,叫法
ParOldGen Parallel Old Generation //新生代和老年代垃圾回收器,叫法
上图显示的是新生区和老年区可以使用垃圾回收器的所有种类,我们一个一个来说明
「新生代」使用Serial Coping垃圾回收器使用「复制算法」
「老年区」默认使用Serial Old垃圾回收器,使用「标记清除算法和标记整理算法」
通过-XX:+UseSerialGC设置

「新生区」使用ParNew垃圾回收器,使用复制算法
「老年区」使用Serial Old垃圾回收器(不推荐这样使用),使用标记清除算法和标记整理算法
通过-XX:+UseParNewGC启动

「新生代」使用并行垃圾回收
「老年代」使用并行垃圾回收。Java1.8中默认使用的垃圾回收器
「一个问题:Parallel和Parallel Scavenge收集器的区别?」
Parallel Scavenge收集器类似于ParNew也是一个新生代的垃圾收集器,使用了复制算法,也是一个并行的多线程的垃圾收集器,俗称吞吐量优先收集器。
parallel Scavenge是一种自适应的收集器,虚拟机会根据当前系统运行情况收集性能监控信息,动态调整这些参数以提供最合适的提顿时间或者最大吞吐量
「他关注的点是:」
可控制的吞吐量。吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),
同时,当新生代选择为Parallel Scavenge的时候,会默认激活老年区使用并行垃圾回收
通过-XX:UseParallelGC或者-XX:UseParallelOldGC两者会互相激活

「-XX:ParallelGCThreads=n表示启动多少个GC线程」
cpu>8时 N=5或者8
cpu<8时 N=实际个数
Serial Old是Serial垃圾收集器老年代版本,是一个单线程的收集器,使用「标记整理算法」,运行在Client中的年老代垃圾回收算法
与新生代的Serial GC相关联
Parallel Old/采用「标记整理算法」实现
与新生代的Parallel Scavenge GC相关联
CMS收集器(Concurrent Mark Sweep并发标记清除):一种以获取最短回收停顿时间为目标的收集器
适合应用在互联网站或者B/S系统的服务器上,重视服务器的响应速度
CMS非常适合堆内存大、CPU核数多的服务端应用,也是G1出现之前大型应用的首选收集器
「标记的时候,GC线程运行;清除的时候和用户线程一起运行」
通过-XX:+UseConcMarkSweepGC指令开启
配合「新生区的pallellal New GC回收器使用」
「当CMS由于CPU压力太大无法使用的时候会使用SerialGC作为备用收集器」

CMS initial mark)。遍历寻找到所有的GCRoots。GC线程执行,用户线程暂停CMS concurrent mark)和用户线程一起遍历GCRoots,标记需要清除的对象CMS remark)。修正标记期间,对因用户程序继续运行而不需要进行回收的对象进行修正CMS concurrent sweep)和用户线程一起清除所有标记的对象
「优点:」
「缺点:」
参数(-XX:+……) | 新生代垃圾回收器 | 新生代算法 | 老年代垃圾回收器 | 老年代算法 |
|---|---|---|---|---|
UseSerialGC | SerialGC | 复制算法 | Serial Old GC | 标整 |
UseParNewGC | Parallel New GC | 复制算法 | Serial Old GC | 标整 |
UseParllelGC | Parallel Scavenge GC | 复制算法 | Parallel GC | 标整 |
UseConcMarkSweepGC | Parallel New GC | 复制算法 | CMS和Serial Old GC | 标清 |
UseG1GC | 整体标整 | 局部复制 |
「垃圾回收算法通用逻辑」

java内存模型。是一种规范。
「线程在操作变量的时候,首先从物理内存中复制一份到自己的工作内存中(栈内存),更新以后再写入物理内存中」
「特点:」
