标签:
首先什么是内存泄漏,简单点说就是用完了忘了回收,而其他对象等资源想用却没法用的一种“站着茅坑不拉屎”的浪费资源的情况。在C/C++中,多数泄漏的场景就是程序离开某一运行域时,如在某个方法体中new出的对象或者malloc出的结构体等,并且只有该方法体中的局部变量指向这块内存区域时,在该方法返回时,存在栈中的局部变量指针随着栈帧被一起销毁,那么就没有任何指针可以指向该内存区域了,那么这块内存区域便是泄漏了。
而java的内存泄漏呢?众所周知,java的内存回收是由gc管理的。gc运行的是可达性算法,jvm中的gc线程将java对象从一个特定的对象gcroot开始,看成一个树,遍历树以判断对象的可达性,和C++那种静态的指针计数拥有本质区别,不存在无用对象间相互引用造成的困扰。也就是说当java对象真正确实没有任何一个(强)引用(弱引用等除外)的时候,java对象才可能会被回收。也就是说,这里的java内存泄漏和传统的C/C++是不尽相同的。
下图是java的可达性算法:
# instance fields .field final synthetic this$0:Lcom/gy/just/VoltageMonitor/View/Activity/YunWeiActivity; .field final synthetic val$sec:I # direct methods .method constructor <init>(Lcom/gy/just/VoltageMonitor/View/Activity/YunWeiActivity;I)V .locals 0 .param p1, "this$0" # Lcom/gy/just/VoltageMonitor/View/Activity/YunWeiActivity;编译器自动给内部类加了一个叫“this$0”的外部类变量,并且在构造函数中赋值。那么内部类中就持有有了一个不可见的外部类强引用。像Runnable,Handler这类的内部类如果子线程没有结束的话,那么外部类对象的泄漏就容易发生了。
public class B extends A{ public void test(){ new Thread(new Demo()).start(); } @Override public void dosth() { // TODO Auto-generated method stub System.out.println("doB"); } class Demo implements Runnable{ public Demo(){ try { Field field = getClass().getDeclaredField("this$0"); field.setAccessible(true); field.set(this, null); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void run() { // TODO Auto-generated method stub dosth(); } } }运行异常如下
public abstract interface java.util.List<E> Exception in thread "Thread-0" java.lang.NullPointerException at test.B$Demo.run(B.java:46) at java.lang.Thread.run(Thread.java:745)
标签:
原文地址:http://blog.csdn.net/ganyao939543405/article/details/52229059