ThreadLocal内存泄漏分析

共 9556字,需浏览 20分钟

 ·

2021-05-16 12:06

点击上方蓝色字体,选择“标星公众号”

优质文章,第一时间送达

76套java从入门到精通实战课程分享

引言

啥是内存泄漏??
好像一直不明白啥叫内存泄漏,对于java来说,就是堆中对象已经不会再被使用了,但是垃圾收集器却不能将他们从内存中清除。
关键词:对象已经不会再被使用垃圾收集器不能清除
垃圾收集器不能清除表示这个对象肯定还可达,也就是还有GC root可以到这个对象引用链。但是这个对象对于我们程序员来说已经没有用了,也就是我们程序员不会在使用这个对象。对象已经不会再被使用

ThreadLocal内存泄漏的原因

啥原因呢?你因该知道ThreadLocal的set是存到当前线程对象的ThreadLocalMap中,当栈中对ThreadLocal对象的引用释放后,GC后ThreadLocalMap中的key就指向了null,但是value还是指向你set的对象。注意对当前线程对象的引用还在,也就是还有当前对象一直可达,这样就导致当前线程对象的ThreadLocalMap中的key为null,value不为空。value一直没有办法释放。

代码验证

package quickstart;

import java.util.ArrayList;
import java.util.List;

public class TestThreadLocalMemoryLeak {
    public static void main(String[] args) {
        ttt(null);
        while (true){
            try{
                Thread.sleep(1000 * 2);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    public static void ttt(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("==================");
                leak();
                try{
                    Thread.sleep(1000 * 60);
                }catch (Exception e){
                    e.printStackTrace();
                }

            }

            private void leak(){
                List<Double> list = new ArrayList<>();
                for (int i = 0; i < 10000000; i++) {
                    list.add(Math.random());
                }

                ThreadLocal<List> listThreadLocal
                        = new ThreadLocal<>();
                listThreadLocal.set(list);
            }
        };


        Thread thread = new Thread(runnable);
        System.out.println("thread start");
        thread.start();
        try{
            thread.join();
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("thread end");
    }
}

结果如下图:在thread死亡之前,点击“执行垃圾回收”按钮对堆的大小没有作用,当线程退出的时候,GC很快,效果也很明显。

你能明白下面的程序为啥不会构成内存泄漏吗?

package quickstart;

        import java.util.ArrayList;
        import java.util.List;

public class TestThreadLocalMemoryLeak {
    public static void main(String[] args) {
        ttt(null);

    }
    public static void ttt(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("==================");
                leak();
                try{
                    Thread.sleep(1000 * 60);
                }catch (Exception e){
                    e.printStackTrace();
                }

            }

            private void leak(){
                List<Double> list = new ArrayList<>();
                for (int i = 0; i < 10000000; i++) {
                    list.add(Math.random());
                }

                ThreadLocal<List> listThreadLocal
                        = new ThreadLocal<>();
                listThreadLocal.set(list);
            }
        };


        Thread thread = new Thread(runnable);
        System.out.println("thread start");
        thread.start();
        try{
            thread.join();
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("thread end");


        while (true){
            try{
                Thread.sleep(1000 * 2);
                 System.out.println(thread);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

因为栈中一直引用着线程。但是线程中的ThreadLocalMap已经变成null了。



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:

https://blog.csdn.net/xiaolixi199311/article/details/116565875





粉丝福利:Java从入门到入土学习路线图

👇👇👇

👆长按上方微信二维码 2 秒


感谢点赞支持下哈 

浏览 16
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报