java实现匿名接口内存泄漏_Java匿名对象导致的内存泄漏

这几天与在某群与群友讨论了Runnable匿名对象导致内存泄漏的相关问题,特此记录一下。

示例代码如下:

packagecom.memleak.memleakdemo;public class Leaker {

String valueToRead= "Hello world";public voiddoSomething()

{

Thread bgThread= newThread(newRunnable()

{public voidrun() {while (true)

{

System.out.println("Running... ok");try{

Thread.sleep(1000);

}catch(InterruptedException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

);

bgThread.start();

}

}

Main函数:

packagecom.memleak.memleakdemo;/*** Hello world!

**/

public classApp

{public static voidmain( String[] args )

{

Leaker l= newLeaker();

l.doSomething();

}

}

问题出在哪?

启动此程序,main函数对应的线程在调用Leaker之后,应该退出了,后台只有一个Runnable在执行,理论上此时Leaker对象没有任何东西引用,此时应该被GC才对,但是如果使用visualVM查看下内存:

java实现匿名接口内存泄漏_Java匿名对象导致的内存泄漏_第1张图片

即使强制GC之后,此对象依旧存在,说明发生了泄露。

在上面图中的例子使用了一个匿名的Runnable对象,如果将此Runnable改为一个显式声明的对象,如下例子所示:

packagecom.memleak.memleakdemo;public class CauseLeakerNotToLeak implementsRunnable {public voidrun() {while (true)

{

System.out.println("Running... ok");try{

Thread.sleep(1000);

}catch(InterruptedException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

LeakerSolved.java

packagecom.memleak.memleakdemo;public classLeakerSolved {

String valueToRead= "Hello world";public voiddoSomething()

{

Thread bgThread= newThread(newCauseLeakerNotToLeak()

);

bgThread.start();

}

}

通过VisualVM则会发现已经不再泄露了:

当然,如果使用Java 8带的Lambda表达式:

packagecom.memleak.memleakdemo;public classLeakerLambda {

String valueToRead= "Hello world";public voiddoSomething()

{

Thread bgThread= new Thread(() -> {while(true) {

System.out.println("Running... ok");try{

Thread.sleep(1000);

}catch(InterruptedException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}});

bgThread.start();

}

}

也能解决这个问题:

java实现匿名接口内存泄漏_Java匿名对象导致的内存泄漏_第2张图片

结论:

在创建线程的时候一定要谨慎使用匿名Runnable对象,最好使用命名对象或者Lambda表达式代替。

原文:https://www.cnblogs.com/nullifier/p/12356935.html

你可能感兴趣的:(java实现匿名接口内存泄漏)