JVM垃圾回收概念

一、System.gc()

- 默认,通过System.gc() 或 Runtime.getRuntime().gc(), 会触发  Full GC
  Full GC 会同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存

- 无法保证堆垃圾收集器的调用, 可以通过 重写finalize()来判断

- 一般情况下,垃圾回收自动进行,无须手动触发
 特殊情况下,可以显示调用来做基准测试

二、内存泄漏/内存溢出

1. 内存溢出(OOM)

1. 应用程序占用的内存增长速度快,快速占用了JVM的所有内存

2. 进行一次独占式的 Full GC 操作后,回收大量内存

OOM: 没有空闲内存,并且垃圾回收器回收完后,依然无法提供更多内存
  • 原因下面两个:
  • Java虚拟机的堆内存设置不够
  • 代码中创建了大量大对象,并且长时间不能被垃圾收集器收集,存在被引用

2. 内存泄漏

  • Memory Leak
- 严格来说,  只有对象不会再被程序用到了,但是GC又不能回收他们,才叫做内存泄漏
- 实际情况:  意外导致对象的生命周期变得很长甚至导致OOM,也可以叫做内存泄漏
            比如类的static属性

- 内存泄漏可能会逐步消耗可用内存空间,直到耗尽所有内存,最终出现 OutOfMemory
example1: 单例模式
- 单例的生命周期和应用程序是一样长的,如果单例程序中持有对外部对象的引用,那么这个外部对象是不可能
被回收的,则会导致内存泄漏的产生

- 一些提供close的资源未关闭导致内存泄漏
  比如socket,io,datasource等的链接,如果不手动close, 则是不能回收的

三、Stop The World

  • Stop-The-World: 在GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应,有点卡死的感觉,停顿就是STW
可达性分析算法中枚举根节点会导致所有java执行线程停顿
- 分析工作必须在一个能确保一致性的快照中进行
- 一致性指整个分析期间,整个执行系统看起来像是被冻结在某个时间点上
- 如果出现分析过程中对象引用关系还在不断变化,则分析结果的准确性无法保证

被STW 中断的应用程序,会在完成GC 后回复,频繁中断会让用户感觉多个卡顿,所以需要减少STW的产生
1. STW和哪款GC无关,所有的GC 都有这个事件
2. 只能说垃圾回收器越来越优秀,回收效率越来越高,尽可能的缩短了暂停时间
3. STW 是JVM在后台自动发起和自动完成的。在用户不可见的情况下,把用户正常的工作线程全部停下来
4. 开发中不要用System.gc(), 会导致STW的发生

四、安全点和安全区域

程序执行时,并非在所有地方都能停顿下来开始GC,只有在特定的位置才能停顿下来开始GC
这些位置称为   安全点 -  Safepoint

- Safe Point的选择很重要
- 如果太少,则等待GC的时间太长,就会导致oom
- 如果太多,则频繁的gc,导致运行时的性能问题

大部分指令的执行时间都非常短暂
通常会根据 “是否具有让程序长时间执行的特征”为标准
- 比如选择一些执行时间较长的指令作为  Safe Point,比如方法调用,循环跳转,异常跳转
安全区域: 在一段代码片段中,对象的引用关系不会发生变化,在这个区域中的任何位置开始GC都是安全的

可以把Safe Region看作是扩展了的 SafePoint

五、引用

  • JDK 1.2后, Java对引用的概念进行了扩充
  • 强引用,Strong Reference
  • 软引用, Weak Reference
  • 弱引用, Weak Reference
  • 虚引用, Phantom Reference
  • 强软弱虚,引用强度依次逐渐减弱
  • 除强引用外,其他3种引用均可以在java.lang.ref包中找到,可以直接使用

在这里插入图片描述

  • 上述不同的引用,均指的是在引用还存在的前提下,垃圾回收器是否会进行回收

1. 强引用

  • 只要引用存在,那么就不会回收
  • 强引用的对象是可触及的,只要引用没有断开,则永远不会被回收
  • 强引用是内存泄漏的主要原因
  • 强引用指的就是一般的那种通过new来创建出来的对象

2. 软引用

  • 内存不足才会回收
用来描述一些还有用,但并非必须的对象
- 软引用关联的对象,在系统将要发生oom的时候,会把软引用的对象,列入回收范围内进行
  第二次回收
- 如果这次回收还没有足够的内存,才会抛出内存溢出

比如实现内存敏感, 高速缓存

垃圾回收器在某个时刻决定回收软可达的对象时,会清理软引用
可选的把软引用存放倒一个引用队列(Reference Queue中)
package com.nike.erick;

import java.lang.ref.SoftReference;

public class Demo01 {
    public static void main(String[] args) {
        Object obj = new int[1024];

        SoftReference<Object> softReference = new SoftReference<>(obj);

        // 将强引用断开
        obj = null;

        System.out.println("Before GC" + softReference.get());
        System.gc();
        System.out.println("After GC" + softReference);
    }
}

3. 弱引用

  • 弱引用是用来描述那些非必须对象,只被弱引用关联的对象,只能生存到下一次垃圾收集发生为止
  • 系统发生GC时候,只要发现弱引用,不管系统堆空间使用是否充足,都会回收掉只被弱引用关联的对象
  • 存放缓存数据
  • 弱引用相比软引用,更容易被发现和回收,速度更快
  • WeakHashMap
package com.nike.erick;

import java.lang.ref.WeakReference;

public class Demo01 {
    public static void main(String[] args) {
        Object obj = new int[1024];

        WeakReference<Object> weakReference = new WeakReference<>(obj);

        // 将强引用断开
        obj = null;

        System.out.println("Before GC" + weakReference.get());
        System.gc();
        System.out.println("After GC" + weakReference);
    }
}

4. 虚引用

  • Phantom Reference, 对象回收跟踪
  • 一个对象是否有虚引用的存在,完全不会决定对象的生命周期。如果一个对象仅仅持有虚引用,那么它和没有引用几乎是一样的,随时都可能被垃圾回收器回收
  • 它不能单独使用,也无法通过虚引用来获取被引用的对象。当试图通过虚引用的get方法获取对象时,总是null
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值