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了。