JVM 垃圾回收算法介绍

对象是否存活

1、引用计数算法

在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的对象就是不可能再被使用的
优点:效率高,简单
缺点:无法解决循环引用问题

2、可达性分析算法

通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节
点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”(Reference
Chain),如果某个对象到 GC Roots 间没有任何引用链相连,或者用图论的话来说就是
从 GC Roots 到这个对象不可达时,则证明此对象是不可能再被使用的

在 Java 技术体系里面,固定可作为 GC Roots 的对象包括以下几种:

  • ·在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法 堆栈中使用到的参数、局部变量、临时变量等。
    ·
  • 在方法区中类静态属性引用的对象,譬如 Java 类的引用类型静态变量。 ·在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。
  • 在本地方法栈中 JNI(即通常所说的 Native 方法)引用的对象。
  • Java虚拟机内部的引用,如基本数据类型对应的 Class 对象,一些常驻的异常对象 (比如
    NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
  • 所有被同步锁(synchronized关键字)持有的对象。 ·反映 Java 虚拟机内部情况的 JMXBean、JVMTI中注册的回调、本地代码缓存等

引用类型

  1. 强引用 —— 代码中的引用赋值
  2. 软引用 —— 一些还有用,但是非必要的对象,系统内存溢出前,会对其进行二次回收
  3. 弱引用 —— 在回收的时候必定会被回收
  4. 虚引用 —— 虚幻引用,只是为了在系统回收该对象时获取一个通知

垃圾收集算法

1、标记清除算法

过程:先标记内存区可回收的对象,标记完成后统一回收掉标记的对象
缺点:1、执行效率不稳定,对象越多,效率越慢
2、回收后存在碎片空间问题
老年代

2、标记复制算法

过程:将内存分片分成两个,留下一个区域不用,当回收时将存活的对象,复制到不用的内存区,在清除掉原来的内存
缺点: 1、会造成空间的浪费(可以调整为8:1:1)

3、标记整理算法

过程:的标记过程仍然与“标记-清除”算法一样,标记结束后所有存活的对象都向内存空间一端移
动,然后直接清理掉边界以外的内存

垃圾收集器

1、Serial 收集器

它进行垃圾收集时,必须暂停
其他所有工作线程,直到它收集结束(新生代)

2、 ParNew 收集器

ParNew 收集器实质上是 Serial 收集器的多线程并行版本 (新生代)

3、Parallel Scavenge 收集器

追求吞吐量的收集器

吞吐量= 运行用户代码时间/(运行代码时间+垃圾收集时间)

4、Serial Old 收集器

erial Old 是 Serial 收集器的老年代版本,它同样是一个单线程收集器,使用标记整理算法。

5、Parallel Old 收集器

Parallel Old 是 Parallel Scavenge 收集器的老年代版本,支持多线程并发收集,基于
标记-整理算法实现。

6、CMS 收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收
集器(老年代-标记清除算法)

7、Garbage First 收集器、

虽然 G1 仍然保留新生代和老年代的概念,但新生代和老年代不再是固定的了,它
们都是一系列区域(不需要连续)的动态集合
G1回收器的步骤:
1、初始标记’
2、并发标记
3、最终标记
4、筛选回收

ThreadLocal 内存泄漏分析

什么是ThreadLocal

/* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }                                                                                                                                                                                                                                                                                                      
        }

ThreadLocal的实现原理,每一个Thread维护一个ThreadLocalMap,key为使用弱引用的ThreadLocal实例,value为线程变量的副本。这些对象之间的引用关系如下

请添加图片描述

![实心箭头表示强引用,空心箭头表示弱引用](https://img-blog.csdnimg.cn/49fea048fed244308999f016a830bd07.png

ThreadLocaL 和 ThreadLocalMap 都是放在堆区的,堆区就存在内存回收操作

在项目中使用线程时,我们默认都会使用线程池,在线程池中,核心线程是不会销毁的,在一个任务执行完后,会被继续用来执行新的任务,也就是说在java的static中会一直存在一个当前线程强引用,而threaLocalRef会被弹出,当发生标记行为时,应为thread只有一个弱引用,就会被标记成可回收对象,回收后当前threadLocal就会被置为null,然而,value应为一直存在 Currentthread——threadLocaLMap——enter—value 强引用,所以一直不会被回收,此时就会发生内存泄漏现象。

为啥 enter到Thread为弱引用

弱引用ThreadLocal不会内存泄漏,对应的value在下一次ThreadLocalMap调用set(),get(),remove()的时候会被清除。

解决方法

  1. 每次使用完ThreadLocal都调用它的remove()方法清除数据
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值