AndroidAndroid

Android之内存溢出和内存泄漏的原因和解决方案

2018-11-20  本文已影响115人  yujunjun

基础

JAVA是在JVM所虚拟出的内存环境中运行的,内存分为三个区:堆、栈和方法区。

概念

关系

危害

判断是否有内存泄露的工具

LeackCanary

Memory Monitor

DDMS

处理方式汇总

强引用,软引用和弱引用

大量的图片、音频、视频处理,当在内存比较低的系统上也容易造成内存溢出

Bitmap对象的处理

非静态内部类和匿名內部类Handler、Thread、Runnable等由于持有外部类Activity的引用,从而关闭activity,线程未完成造成内存泄漏

在线程休眠的这10s内,会一直隐式持有外部类的引用MainActivity,如果在10s之前,销毁MainActivity,就会报内存泄漏。同理,若是这个Thread作为MainActivity的内部类而不是匿名内部类,也会内存泄漏。
总而言之:如果Activity在销毁之前,任务还未完成, 那么将导致Activity的内存资源无法回收,造成内存泄漏。
解决办法:在这里只需要将为Thread匿名类定义成静态的内部类即可(静态的内部类不会持有外部类的一个隐式引用)。或保证在Activity在销毁之前,完成任务!

资源未及时关闭造成的内存泄漏

对于使用了BraodcastReceiver,ContentObserver,Cursor,File,Stream,ContentProvider,Bitmap,动画,I/O,数据库,网络的连接等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。

注销监听器

static关键字修饰的变量由于生命周期过长,容易造成内存泄漏

如果使用Context ,尽可能使用Applicaiton的Context

这是一个普通的单例模式,当创建这个单例的时候,由于需要传入一个Context,所以这个Context的生命周期的长短至关重要:
1、传入的是Application的Context:这将没有任何问题,因为单例的生命周期和Application的一样长 ;
2、传入的是Activity的Context:当这个Context所对应的Activity退出时,由于该Context和Activity的生命周期一样长(Activity间接继承于Context),所以当前Activity退出时它的内存并不会被回收,因为单例对象持有该Activity的引用。
所以正确的单例应该修改为下面这种方式:

    public class TestManager {
        private static TestManager instance;
        private Context context;
    
        private TestManager(Context context) {
            this.context = context.getApplicationContext();
        }
    
        public static TestManager getInstance(Context context) {
            if (instance != null) {
                instance = new TestManager(context);
            }
            return instance;
        }
    }

这样不管传入什么Context最终将使用Application的Context,而单例的生命周期和应用的一样长,这样就防止了内存泄漏。

不要使用String进行字符串拼接

三方库

上一篇 下一篇

猜你喜欢

热点阅读