JVM虚拟机和GC垃圾回收

平台无关 一次编译到处运行
  • javac编译成class字节码 虚拟机加载class文件,将其转换为当前计算机可执行的机器码进行执行
  • javap -c xxx.class
  • jvm屏蔽了计算机操作系统的信息
jvm如何加载.class文件

通过类加载器去找到.class文件最终通过反射来创建(只要知道class 能够获取类的所有东西)

classloader种类
  • BootstrapClassLoader C++编写 加载核心库 java.*
  • ExtClassLoader java编写 加载javax.*
  • AppClassLoader java编写 加载程序路径下的
  • 自定义classloader 定制化加载

java虚拟机内存模型

  • classloader,类加载器
  • runtime data area,运行时数据区(堆,方法区,虚拟机栈,本地方法栈,程序计数器)
  • execution engin,对命令进行解析
  • native interface 本地接口,不同语言的原生库

jvm内存模型的三大特性

  • 原子性:要么执行 要么不执行
  • 可见性:一个线程对共享变量的修改,另一个线程能够看得到(具体的说:在变量修改后将新值同步回主内存,主要有两种实现方式,一是volatile,被volatile修饰的变量发生修改后会立即刷新到主内存;二是使用Synchronize或者lock,当一个变量unlock之前会将变量的修改刷新到主内存中)
  • 有序性:程序执行的顺序按照代码的先后顺序执行。(具体的说:在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序不会影响单线程的执行结果,却会影响多线程并发执行的正确性。主要有两种方式确保有序性:volatile 和 Synchronize 关键字,volatile是通过添加内存屏障的方式来禁止指令重排序,也就是重排序是不能把后面的指令放到内存屏障之前执行;Synchronize是保证同一时刻有且只有一个线程执行同步代码,类似于串联顺序执行代码)。

垃圾回收机制

判断对象是否为垃圾的算法

  1. 引用计数算法
  2. 可达性分析算法
引用计数算法
判断对象的引用数量
  • 通过判断对象的引用数量来决定对象是否可以被回收
  • 每个对象实例有一个引用计数器 被引用+1,完成引用-1
  • 任何引用技术为0的对象实例可以被当作垃圾收集
优点:执行效率高,程序影响小
缺点:无法检测出循环引用的情况,导致内存泄露

ps:内存溢出 内存泄露

可达性分析算法

通过判断对象的引用链是否可达来决定对象是否可以被回收

  • 原理是离散数学的图论 通过一系列的GcRoot作为根节点进行搜索,搜索路径就是引用链 当一个对象从GcRoot没有任何引用链相连,就说这个对象是不可达的,这个对象不可用,标记为垃圾
  • 可以作为GcRoot的对象
  1. 虚拟机栈中引用的对象
  2. 方法区常量引用对象
  3. 方法区中类静态属性引用的对象
  4. 本地方法栈中JNI(Native)的引用对象
  5. 活跃线程的引用对象

垃圾回收算法

标记清除算法

  1. 标记:从根集合进行扫描,对存活对象进行标记(判断是否可达)
  2. 清除:对堆内存从头到尾进行线性遍历,回收不可达对象内存(将没有被标记的对象清除掉)
  • 缺点 碎片化
  • 适用于老年代

复制算法

原理:

  • 分为对象面和空闲面
  • 对象在对象面上创建
  • 存活的对象被从对象面复制到空闲面
  • 将对象面多有对象内存清除

优缺点:

  • 解决碎片化的问题
  • 顺序分配内存,简单高效
  • 适用于对象存活率低的场景
  • 对象存活率高的时候不适用 会浪费50%的空间
  • 适用于新生代

标记整理算法

原理:

  1. 标记:从根集合进行扫描,对存活对象进行标记(判断是否可达)
  2. 清除整理:移动所有存活对象按照内存地址次序依次排列,然后末端内存地址以后的内存全部回收

优缺点:

  • 避免内存的不连续
  • 不用设置两块内存交换
  • 适用于存活率高的场景
  • 适用老年代

分代收集算法(常用垃圾收集器使用的)

  • 垃圾回收算法的组合拳
  • 按照对象生命周期的不同划分区域以采用不同的垃圾回收算法
  • 目的:提高JVM的回收效率
  • 主流的收集算法
jvm内存空间
  1. 在1.7及以前分为 老年代 年轻代 永久代
  2. 从1.8开始 没有永久代了
  3. 年轻代存活率低 采用复制算法 老年代采用标记清除算法、标记整理算法
年轻代 1/3内存空间
  • 组成
  1. Eden区间 80% 新创建的对象都在这里面
  2. 两个Survivor区 各占10%
  • 作用 尽可能快速的收集掉那些生命周期短的对象
  • 收集过程
  1. 当Eden区满了 触发一次MinorGc,会将存活对象复制到S0,计数加1,清除Eden区所有空间。
  2. 当Eden又满了,又一次触发MinorGc,会将Eden区和S0存活对象复制到S1,计数加1,清除Eden和S0
  3. 再一次满了 又会将Eden和S1复制到S0,计数加1
  • 怎样晋升到老年大
  1. 当年龄达到一定数(默认15)将会存入老年代
  2. 在年轻代survivor装不下的对象也会直接进入老年代
  3. 有对应的参数
老年代 2/3
  • 存放生命周期长
  • 收集算法 标记清理、标记整理
  • 老年代垃圾回收
  1. FullGc和MajorGc
  2. FullGc比MinorGc慢 执行频率低(因为老年代的对象一般存活率都比较高)
  • FullGc触发条件
  1. 老年代空间不足
  2. 永久代空间不足(1.8之前)
  3. CMSGC 收集出现异常
  4. MinorGc晋升到老年代的平均大小大于老年代剩余空间
  5. 调用System.gc
  6. 使用RMI来进行RPC或管理的JDK应用,每小时执行一次Full GC
stop the world
  • 执行Gc而停止应用程序的执行
  • 任何一种Gc都会发生
  • 多数Gc通过优化减少发生时间提高程序性能,高吞吐 低停顿
SafePoint 安全点
  • 分析过程中对象引用关系不会发生变化的点
  • 产生安全点的地方:方法调用;循环跳转;异常跳转
  • 安全点的数量需适中
jvm运行模式
  • Server 重量级虚拟机 启动慢 稳定和快
  • Client 轻量级 启动快

常见垃圾收集器 hospot

年轻代常见垃圾收集器

1: Serial收集器(-XX:+UseSerial 复制算法)

  • 单线程收集,进行垃圾收集时,必须暂停所有工作线程
  • 简单高效 client模式下默认的年轻代收集器
  1. ParNew收集器(-XX:+UseParNewGC 复制算法)
  • 多线程收集,其余行为、特点和Serial收集器一样
  • 单核情况下效率不如Serial,多核下执行才有优势
  • 关注系统停顿时间
  1. Parallel Scavenge收集器(-XX:UserParallelGC 复制算法)
  • 系统吞吐量 = 运行用户代码时间/(运行用户代码时间+垃圾收集时间)
  • 和ParNew类似
  • 关注系统吞吐量
  • Server模式下默认的年轻代收集器
老年代常见垃圾收集器
  1. Serial Old收集器(-XX:+UseSerialOldGC b标记-整理算法)
  • 单线程收集,进行垃圾收集时,必须暂停所有工作
  • 简单高效,Client模式下默认的老年代收集器
  1. Parallel Old收集器(-XX:+UseParallelOldGC 标记-整理算法)
  • 多线程,吞吐量优先 和Parallel Scavenge收集器配合使用
  1. CMS收集器(-XX:+UseConcMarkSweepGC 标记-清除算法)
  • 收集线程和应用程序线程几乎同步
  • 老年代主要垃圾收集器

步骤

    • 初始标记:stop-the-world
    • 并发标记:并发追溯标记,程序不会停顿
    • 并发预清理: 查找执行并发标记阶段从年轻代晋升老年代的对象
    • 重新标记:暂停虚拟机,扫描SCM堆中剩余的对象
    • 并发清理:清理垃圾对象,程序不会停顿
  • 并发重置:重置CMS收集器的数据结构
  1. G1收集器(-XX:+UseG1GC,复制+标记-整理算法)
  • Garbage First
  • 将整个java堆内存划分成多个大小相等的Region
  • 年轻代和老年代不在物理隔离

GC相关

  1. Object的finalize()方法
  • 给与对象最后一次重生机会

强引用、软引用、弱引用、虚引用

  1. 强引用
  • 最普遍的引用:Object obj = new Object();
  • 抛出OOM异常终止程序也不会回收强引用的对象
  • 通过将对象设置为null来弱化引用,使其被回收
  1. 软引用(Soft Reference)
  • 对象处在有用但非必须的状态
  • 只有当内训空间不足时,GC会回收该引用对象的内存
  • 可以用来实现高速缓存
String str = new String("java");
SoftReference<String> softRef = new SoftReference<String>(str);
  1. 弱引用(Weak Reference)
  • 非必须的对象,比软引用更弱一些
  • GC时会被回收
  • 被回收的概率也不是太大,因为GC线程优先级比较低
  • 适用于引用偶尔被使用且不影响垃圾收集的对象
String str = new String("java");
WeakReference<String> weakReference = new WeakReference<>("str");
  1. 虚引用(PhantomReference)
  • 不会决定对象的生命周期
  • 任何适合都可能被垃圾收集器回收
  • 跟踪对象被垃圾收集器回收的活动,起哨兵作用
  • 必须和引用队列ReferenceQueue联合使用
String str = new String("java");
ReferenceQeueu qeueu = new ReferenceQeueu();
PhantomReference ref = new PhantomReference(str,qeueu);
  1. 总结对比
    强>软>弱>虚
引用类型被垃圾回收的时间用途生存时间
强引用从来不会对象的一般状态jvm停止运行时终止
软引用内存不足时对象缓存内存不足时
弱引用在垃圾回收时对象缓存GC运行后终止
虚引用Unknown哨兵、标记Unknown

ReferenceQueue 引用队列 无存储结构

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值