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();  
                    }  
                }  
            }  
        }          
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM