• Android内存泄露分析之StrictMode


    转载请注明地址:http://blog.csdn.NET/yincheng886337/article/details/50524709

    StrictMode(严格模式)使用

    StrictMode严格模式,主要用来检测程序中违例情况的开发者工具。最常用的场景就是检测主线程中本地磁盘、网络读写等耗时的操作以及Activity泄露等,但该模式不建议在Release版本开启,此外该模式无法监控JNI中的磁盘IO和网络请求且其违例情况仅供参考,需结合实际开发需求予以解决。

    StrictMode检测什么?

    主要采用采用ThreadPolicy(线程策略)和VmPolicy(Vm策略)进行检测,各策略检测内容如下:

    ThreadPolicy

    线程策略检测的内容有

    · 自定义的耗时调用 使用 detectCustomSlowCalls() 开启

    · 磁盘读取操作 使用 detectDiskReads() 开启

    · 磁盘写入操作 使用 detectDiskWrites() 开启

    · 网络操作 使用 detectNetwork() 开启

    VmPolicy

    虚拟机策略检测的内容有

    · Activity泄露 使用 detectActivityLeaks() 开启

    · 未关闭的Closable对象泄露 使用 detectLeakedClosableObjects() 开启

    · 泄露的Sqlite对象 使用 detectLeakedSqlLiteObjects() 开启

    · 检测实例数量 使用 setClassInstanceLimit() 开启

    StrictMode具体使用

    public class DebugUtil {  
        public static void startStrictModeVmPolicy(){  
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()  
            .detectActivityLeaks()/*检测Activity内存泄露*/  
            .detectLeakedClosableObjects()/*检测未关闭的Closable对象*/  
            .detectLeakedSqlLiteObjects() /*检测Sqlite对象是否关闭*/     
            /*也可以采用detectAll()来检测所有想检测的东西*/  
            .penaltyLog().build());  
        }  
        public static void startStrictModeThreadPolicy(){  
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()  
            .detectDiskReads()/*磁盘读取操作检测*/  
            .detectDiskWrites()/*检测磁盘写入操作*/  
            .detectNetwork() /*检测网络操作*/     
            /*也可以采用detectAll()来检测所有想检测的东西*/  
            .penaltyLog().build());  
    }  
    }

    如果你想检测整个App或某Activity的相关泄露问题,可在Application或Activity的onCreate方法中直接调用DebugUtil中封装好的策略即可

    如何查看检测结果?

    只需要查看TAG为StrictMode的日志即可,如:logcat -c;logcat -s StrictMode 或者adb logcat | grep StrictMode

    如何解决检测出来的问题?

    针对此问题下面给出几点建议,仅供参考:

    1.如果是主线程中出现文件读写违例问题,建议使用工作线程(可采用HandlerThread,IntentService、线程池或直接new Thread,必要时可结合Handler)完成,但采用工作线程在某个Activity中操作时注意线程要能正常结束,否则将导致内存泄露,相关细节后文将有表述。

    2.如果是对SharedPrefrences写入操作,在API 9以上建议优先调用apply而非commit,此外需注意的是确保SharedPrefrences在单进程中使用,如果涉及跨进程数据交换,建议自己编写跨进程SharedPrefrences实现机制,否则可能导致数据不准确。

    3.如果存在未关闭的Closable对象,需根据对应的stacktrace进行关闭。

    4.如果SQLite对象泄露,根据对应的stacktrace进行释放。

    5.注意registerBroadcast和unregisterBroadcast配对使用,对文件操作完成后记得close操作。

    StrictMode使用示例

    现以主线程中文件读写为例,引起违例警告的代码如下:

    public void writeToExternalStorage() {  
            File externalStorage = Environment.getExternalStorageDirectory();  
            File destFile = new File(externalStorage, "dest.txt");  
            try {  
              OutputStream output = new FileOutputStream(destFile, true);  
                output.write("droidyue.com".getBytes());  
                output.flush();  
                output.close();  
            } catch (FileNotFoundException e) {  
                  e.printStackTrace();  
            } catch (IOException e) {  
              e.printStackTrace();  
            }  
        }

    StrictMode违例警告:

    D/StrictMode( 9730): StrictMode policy violation; ~duration=20 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=31 violation=2  
                D/StrictMode( 9730):    at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1176)  
                D/StrictMode( 9730):    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:106)  
                D/StrictMode( 9730):    at libcore.io.IoBridge.open(IoBridge.java:390)  
                D/StrictMode( 9730):    at java.io.FileOutputStream.<init>(FileOutputStream.java:88)  
                D/StrictMode( 9730):    at com.example.strictmodedemo.MainActivity.writeToExternalStorage(MainActivity.java:56)  
                D/StrictMode( 9730):    at com.example.strictmodedemo.MainActivity.onCreate(MainActivity.java:30)  
                D/StrictMode( 9730):    at android.app.Activity.performCreate(Activity.java:4543)

    解决方法:

    public void writeToExternalStorage() {  
            new Thread(){  
                @Override  
                public void run() {  
                    /*将对读写操作移至线程*/  
                    File externalStorage = Environment.getExternalStorageDirectory();  
                    File destFile = new File(externalStorage, "dest.txt");  
                    OutputStream output = null;  
                    try {  
                        output = new FileOutputStream(destFile, true);  
                        output.write("droidyue.com".getBytes());  
                        output.flush();                      
                    } catch (FileNotFoundException e) {  
                          e.printStackTrace();  
                    } catch (IOException e) {  
                      e.printStackTrace();  
                    }finally{  
                        /*对文件操作完成后,注意关闭*/  
                        if(output != null){  
                            output.close();  
                        }  
                    }  
                }  
            }          
        }
  • 相关阅读:
    判断UpLoader是否安装了Flash
    事务
    AMQP
    分布式领域CAP理论
    查看数据库所有表的所有字段
    拼分页方法
    Website English Comments
    SQL语句执行时间测试
    一般处理程序返回json
    MVC Action返回Json
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/6874525.html
Copyright © 2020-2023  润新知