Java中内存泄露场景

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29078329/article/details/78944769

一、什么是内存泄露,为什么会出现内存泄露

    内存泄露是指不再使用的对象由于仍然被其他对象引用导致垃圾收集器不能及时释放这些对象占用的内存从而造成内存空间浪费的现象。从内存泄露的概念我们知道了之所以产生内存内漏,是因为长生命周期的对象持有短生命周期对象的引用,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用,会导致短生命周期对象不能被回收,举个例子更详细的说明一下。

    由图可知对象B的生命周期是t1-t2,对象A的生命周期是t1-t3,A中存在B的引用;在t2-t3,B不再被使用,此时即使GC线程在工作,B占用的内存也不会被回收,因为A中还持有B的引用。假若A还持有着其他对象的引用,那么这些被引用的无用对象都不会被回收,甚至有可能 B 也持有一大堆其他对象的引用, 这些对象由于被 B 所引用,也不会被垃圾收集器所回收, 所有这些无用的对象将消耗大量宝贵的内存空间。

二、Java中内存泄露场景

1、使用静态的集合类
    静态的集合类的生命周期和应用程序的生命周期一样长,所以在程序结束前容器中的对象不能被释放,会造成内存泄露。解决办法是最好不使用静态的集合类,如果使用的话,在不需要容器时要将其赋值为null。


2 、单例模式可能会造成内存泄露
    单例模式只允许应用程序存在一个实例对象,并且这个实例对象的生命周期和应用程序的生命周期一样长,如果单例对象中拥有另一个对象的引用的话,这个被引用的对象就不能被及时回收。解决办法是单例对象中持有的其他对象使用弱引用,弱引用对象在GC线程工作时,其占用的内存会被回收掉,如下示例:

public class SingleTon1 {    
    private static final SingleTon1 mInstance = null;    
    private WeakReference<Context> mContext;  
    private SingleTon1(WeakReference<Context> context) {    
    mContext = new WeakReference<Context>(context);  
    }    
    
    public static SingleTon1 getInstance(WeakReference<Context> context) {    
        if (mInstance == null) {    
            synchronized (SingleTon1.class) {    
                if (mInstance == null) {    
                    mInstance = new SingleTon1(context);    
                }    
            }    
        }    
        return mInstance;    
    }    
}    
  
  
public class MyActivity extents Activity {  
    public void onCreate (Bundle savedInstanceState){  
       super.onCreate(savedInstanceState);  
       setContentView(R.layout.main);  
       SingleTon1 singleTon1 = SingleTon1.getInstance(new WeakReference<Context>(this));  
   }  
  
}  


3 、变量不合理的作用域
如果变量的定义范围大于使用范围,并且在使用完后没有赋值为null的话,会出现内存泄露。定义变量的时候,能定义为局部变量就不要定义为成员变量,或者定义为成员变量的话,在使用完变量后,把变量赋值为null。
4、数据库、网络、输入输出流,这些资源没有显示的关闭
    垃圾回收只负责内存回收,如果对象正在使用资源的话,Java虚拟机不能判断这些对象是不是正在进行操作,比如输入输出,也就不能回收这些对象占用的内存,所以在资源使用完后要调用close()方法关闭。

5、使用非静态内部类

    非静态内部类对象的构建依赖于其外部类,内部类对象会持有外部类对象的this引用,即时外部类对象不再被使用了,其占用的内存可能不会被GC回收,因为内部类的生命周期可能比外部类的生命周期要长,从而造成外部类对象不能被及时回收。解决办法是尽量使用静态内部类,静态内部类只是形式上在外部类的里面,静态内部类不会持有外部类的引用,可以把静态内部类理解成是一个独立的类,和外部类没什么关系。

    引申:为什么非静态内部类对象会持有外部类对象的this引用?

   非静态内部类虽然和外部类写在同一个文件中, 但是编译完成后, 还是生成各自的class文件,通过如下三个步骤,内部类对象通过this访问外部类对象的成员。

1) 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象(this)的引用;

2) 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为内部类中添加的成员变量赋值;

3)在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。






猜你喜欢

转载自blog.csdn.net/qq_29078329/article/details/78944769