Java后端技术全栈|快速掌握并发编程---深入学习ThreadLocal( 四 )


【Java后端技术全栈|快速掌握并发编程---深入学习ThreadLocal】好了上面就大概说了一下对象的四大引用 , 主要本文后面需要用到弱引用 。
ThreadLocal内存泄漏
讲到内存泄漏 , 那我们还是把内存溢出和内存泄漏大致说一下 。
内存溢出
在JVM如果发生内存溢出 , 说明内存不够实用 , 撑爆了 , 也就是我们说的OOM 。 大量内存得不到释放 , 又不断申请内存空间 。
系统内存使用200M , 已经使用了180M , 可是你说你还想使用50M , 于是系统就受不了 。
就像气球一样 , 原本已经到极限了 , 你还是使劲打气 , 很容易就导致气球爆炸了 。
就想你只能扛100斤的东西 , 现在给你200斤 , 肯定受不了 。
内存泄漏
强引用所指向的对象不会被回收 , 可能导致内存泄漏 , 虚拟机宁愿抛出OOM也不会去回收他指向的对象 。 前面说到强引用的时候 , 如果对象一直被引用 , JVM是不会回收他的 , 直到最后系统OOM 。
看过《树先生》电影的人都知道 , 树先生家里的地被别人占用了 , 但是树先生不敢把人家怎么样 。 如果是很多人都去占用树先生家的地和财产 , 到最后树先生不就要饿死么 。 树先生这部电影确实好看 , 看完一遍基本上不知道在说什么 , 主要是树先生幻想得太多 , 很多人看了两遍也不是很懂 。 扯远了 。。。
ThreadLocal内存泄漏
内存泄漏案例
模拟了一个线程数为THREAD_LOOP_SIZE的线程池 , 所有线程共享一个ThreadLocal变量 , 每一个线程执行的时候插入一个大的List集合 , 这里由于执行了500次循环 , 也就是产生了500个线程 , 每一个线程都会依附一个ThreadLocal变量:
publicclassThreadLocalOOMDemo{privatestaticfinalintTHREAD_LOOP_SIZE=500;privatestaticfinalintMOCK_BIG_DATA_LOOP_SIZE=10000;privatestaticThreadLocal<List<User>>threadLocal=newThreadLocal<>();publicstaticvoidmain(String[]args)throwsInterruptedException{ExecutorServiceexecutorService=Executors.newFixedThreadPool(THREAD_LOOP_SIZE);for(inti=0;i<THREAD_LOOP_SIZE;i++){executorService.execute(()->{threadLocal.set(newThreadLocalOOMDemo().addBigList());Threadt=Thread.currentThread();System.out.println(Thread.currentThread().getName());//threadLocal.remove();//不取消注释的话就可能出现OOM});try{Thread.sleep(1000L);}catch(InterruptedExceptione){e.printStackTrace();}}//executorService.shutdown();}privateList<User>addBigList(){List<User>params=newArrayList<>(MOCK_BIG_DATA_LOOP_SIZE);for(inti=0;i<MOCK_BIG_DATA_LOOP_SIZE;i++){params.add(newUser(''Java后端技术全栈'',''123456''+i,''man'',i));}returnparams;}classUser{privateStringuserName;privateStringpassword;privateStringsex;privateintage;publicUser(StringuserName,Stringpassword,Stringsex,intage){this.userName=userName;this.password=password;this.sex=sex;this.age=age;}}}
在设置IDEA或者eclipse中 , 设置JVM参数设置最大内存为-Xmx64m , 以便模拟出OOM:
Java后端技术全栈|快速掌握并发编程---深入学习ThreadLocal
文章图片
然后 , 运行上面的案例
Java后端技术全栈|快速掌握并发编程---深入学习ThreadLocal
文章图片
从上面的案例中我们看到:线程池中的每一个线程使用完ThreadLocal对象之后再也不用 , 由于线程池中的线程不会退出 , 线程池中的线程的存在 , 同时ThreadLocal变量也会存在 , 占用内存!造成OOM溢出!
前面我们分析了Thread、ThreadLocal、ThreadLocalMap三者的关系