JDK 1.5
image.pngJDK 1.8
image.pngJVM组成
- 类加载器(ClassLoader)
- 运行时数据区(Runtime Data Area)(堆、栈)
- 执行引擎(Execution Engine)c++/C
- 本地库接口(Native Interface)
线程共享区
image.png申请空间
image.png线程非共享区
image.png对象回收 ---可达性分析
image.png- 简单来说,将对象及其引用关系看做一张图,选定活动的对象作为GCROOTS;然后跟踪引用链条,如果一个对象和GC Roots之间不可达,也就是不存在引用,那么即可认定为可回收对象。
- GC Root的对象
-
虚拟机栈中正在引用的对象
-
本地方法栈中正在引用的对象
本地方法栈(Native Method Stacks)与 Java 虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的 Native 方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。 -
静态属性引用的对象
Class Dog {
private static Object tail;
} -
方法区常量引用的对象
Class Dog {
private final Object tail;
}
-
- 可以理解为:一个方法执行的时候,会开启一个线程去执行该方法。这个时候就可以当做一个GC Root,它会自动去收集该方法中所有的对象的引用关系,变成一个树结构,当执行完毕就会自动删除GC Root,所有的对象会自动全部释放。
垃圾收集器
新生代老年代 1: 2
老年代:大对象
image.png
- 标记清除算法
- 最基础的收集算法,分为标记和清除两个阶段,首先标记出需要回收的对象,之后由虚拟机统一回收已标记的对象。
- 不足:1.效率问题,标记和清除的效率都不高。2. 空间问题,对象被回收之后会产生大量不连续的内存碎片,当需要分配较大对象时,由于找不到合适的空闲内存而不得不再次触发垃圾回收动作。
- 复制算法
- 将内存划分成大小相等的两部分,每次只使用其中一半,当第一块内存用完了,就把存活的对象复制到另一块内存上。然后清除剩余可回收对象,这样就解决了内存碎片问题。我们只需要异动堆顶指针,按顺序分配内存即可,简单高效。
- 缺点:1.浪费了一半的内存。2.复制这一工作花费时间。
- 引用计数法
- 在每个对象中保存该对象的引用计数,当引用发生增减时对计数进行更新。因此可以释放相应的内存空间。
最后采用:将内存划分新生代和老年代。新生代采用复制算法(多划分S0 S1区),老年代采用标记整理法。合称分代整理算法。
- 关于S0 S1区
- 比例:8:1 : 1(可以调)
- 一个对象进来,如果大对象,直接进入老年代。正常新生内存块如果找不到合适位置(为了保证连续性),触发GC,会把一些活的对象放在S0区。如果S0去满了,新生代正常内存区存活对象有可能直接放到S1,也有可能把S0的对象放到S1去。如果S0和S1都满了,S1里的对象有可能放到老年代(空间窃取现象)--一整个过程都是活的对象,不是垃圾。
老年代的标记整理法
- 标记:它的第一个阶段与标记/清除算法是一模一样的,均是遍历GCROOTt,然后将存活的对象标记。
-
整理:移动所有存活的对象,且按照内存地址次序一次排列,然后将末端内存地址以后的内存全部回收。
image.png
类加载器
分类
-
Bootstrap Loader
- 无应对的Java类,null加载器,加载jre_home/jre/lib目录,或目录配置目录。对应的jdk的核心内库:‘rt.jar’。
-
Extension Class Loader
- 加载jre_home/jre/lib/ex目录,jdk扩展包,或用户配置目录。
-
AppClassLoader
- 负责加载java.class.path指定的目录,用户应用程序classpath或者java命令运行时参数-cp
双亲委派模型(败家子模型)
image.png- 作用
- 像java.lang.Object这些存放在rt.jar中的类,无论使用哪个类加载器加载,最终都会委派给最顶端的启动类加载器加载,从而使得不同加载器加载的Object类都是同一个。
- 为了避免重复加载,由下到上逐渐委托,由上到下逐级查找。
- 首先不会自己去尝试加载类,而是把这个请求委派给父加载器去完成,每一次层级的加载器都是如此,因此所有的类加载器请求都会传给上层的启动类加载器。
- 只有当父加载器反馈自己无法完成该加载请求时,子加载器才会尝试自己去加载。
引用
- 强引用
- 最常见,把一个对象赋给一个引用变量。不可能被gc回收
- 在一个方法的内部有一个强引用,这个引用保存在Java栈中,而真正的引用内容(Object)保存在Java堆中。
- 当这个方法运行完成后,就会退出方法栈,则引用对象的引用数为0,这个对象会被回收。
- 但是如果这个strongReference是全局变量时,就需要在不用这个对象时赋值为null,因为强引用不会被垃圾回收。
- 软引用
- softReference实现。内存足够不回收,内存不足够回收
- 弱引用
- weakReference实现。只要垃圾回收机制一运行就回收
- 虚引用
- PhantomReference实现。不能单独使用,必须和引用队列一起。主要用来跟踪垃圾回收的状态
JVM调优
Snipaste_2020-10-28_21-41-07.png- 堆内存:
- -Xms:初始分配
- -Xmx: 最大
默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。
- 非堆内存:
- -XX:PermSize:初始分配
- XX:MaxPermSize:最大
- 回收器选择:
- 串行收集器:只适用于小数据量的情况
- 并行收集器:吞吐量优先。适用于科学技术和后台处理等
- 并发收集器:响应时间优先。
网友评论