免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
Android內(nèi)存泄露實踐分析
專項:Android內(nèi)存泄露實踐分析
定義
內(nèi)存泄漏也稱作“存儲滲漏”,用動態(tài)存儲分配函數(shù)動態(tài)開辟的空間,在使用完畢后未釋放,結(jié)果導(dǎo)致一直占據(jù)該內(nèi)存單元。直到程序結(jié)束。(其實說白了就是該內(nèi)存空間使用完畢之后未回收)即所謂內(nèi)存泄漏。
內(nèi)存泄漏形象的比喻是“操作系統(tǒng)可提供給所有進(jìn)程的存儲空間正在被某個進(jìn)程榨干”,最終結(jié)果是程序運(yùn)行時間越長,占用存儲空間越來越多,最終用盡全部存儲空間,整個系統(tǒng)崩潰。所以“內(nèi)存泄漏”是從操作系統(tǒng)的角度來看的。這里的存儲空間并不是指物理內(nèi)存,而是指虛擬內(nèi)存大小,這個虛擬內(nèi)存大小取決于磁盤交換區(qū)設(shè)定的大小。由程序申請的一塊內(nèi)存,如果沒有任何一個指針指向它,那么這塊內(nèi)存就泄漏了。
——來自《百度百科》
影響
導(dǎo)致OOM
糟糕的用戶體驗
雞肋的App存活率
成效
內(nèi)存泄露是一個持續(xù)的過程,隨著版本的迭代,效果越明顯
由于某些原因無法改善的泄露(如框架限制),則盡量降低泄露的內(nèi)存大小
內(nèi)存泄露實施后的版本,一定要驗證,不必馬上推行到正式版,可作為beta版持續(xù)觀察是否影響/引發(fā)其他功能/問題
內(nèi)存泄露實施后,項目的收獲:
OOM減少30%以上
平均使用內(nèi)存從80M穩(wěn)定到40M左右
用戶體驗上升,流暢度提升
存活率上升,推送到達(dá)率提升
類型
IO
FileStream
Cursor
Bitmap
Context
單例
Callback
Service
BraodcastReceiver
ContentObserver
Handler
Thread
技巧
慎用Context
Context概念
四大組件Context和Application的context使用參見下表
善用Reference
類型垃圾回收時間生存時間
強(qiáng)引用永遠(yuǎn)不會JVM停止運(yùn)行時終止
軟引用內(nèi)存不足時內(nèi)存不足時終止
弱引用垃圾回收時垃圾回收時終止
虛引用垃圾回收時垃圾回收時終止
Java引用介紹
Java四種引用由高到低依次為:強(qiáng)引用  >  軟引用  >  弱引用  >  虛引用
表格說明
復(fù)用ConvertView
復(fù)用詳解
對象釋放
遵循誰創(chuàng)建誰釋放的原則
示例:顯示調(diào)用clear列表、對象賦空值
分析
原理
Java內(nèi)存分配機(jī)制
Java垃圾回收機(jī)制
根本原因
關(guān)注堆內(nèi)存
怎么解決
詳見方案
實踐分析
詳見實踐
方案
StrictMode
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy
.Builder()
.detectAll()
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy
.Builder()
.detectAll()
.penaltyLog()
.build());
主要檢查項:內(nèi)存泄露、耗時操作等
使用方法:AppContext的onCreate()方法加上
Leakcanary
GitHub地址
使用方法
Leakcanary + StrictMode + monkey (推薦)
使用階段:功能測試完成后,穩(wěn)定性測試開始時
使用方法:安裝集成了Leakcanary的包,跑monkey
收獲階段:一段時間后,會發(fā)現(xiàn)出現(xiàn)N個泄露
實戰(zhàn)分析:逐條分析每個泄露并改善/修復(fù)
StrictMode:查看日志搜索StrictMode關(guān)鍵字
Adb命令
手動觸發(fā)GC
通過adb shell dumpsys meminfo packagename -d查看
查看Activity以及View的數(shù)量
越接近0越好
對比進(jìn)入Activity以及View前的數(shù)量和退出Activity以及View后的數(shù)量判斷
Android Monitor
使用介紹
MAT
使用介紹
實踐(示例)
Bitmap泄露
Bitmap泄露一般會泄露較多內(nèi)存,視圖片大小、位圖而定
經(jīng)典場景:App啟動圖
解決內(nèi)存泄露前后內(nèi)存相差10M+,可謂驚人
解決方案:
App啟動圖Activity的onDestroy()中及時回收內(nèi)存
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
recycleImageView(imgv_load_ad);
}
public static void recycleImageView(View view){
if(view==null) return;
if(view instanceof ImageView){
Drawable drawable=((ImageView) view).getDrawable();
if(drawable instanceof BitmapDrawable){
Bitmap bmp = ((BitmapDrawable)drawable).getBitmap();
if (bmp != null && !bmp.isRecycled()){
((ImageView) view).setImageBitmap(null);
bmp.recycle();
bmp=null;
}
}
}
}
IO流未關(guān)閉
分析:通過日志可知FileOutputStream()未關(guān)閉
問題代碼:
public static void copyFile(File source, File dest) {
FileChannel inChannel = null;
FileChannel outChannel = null;
Log.i(TAG, "source path: " + source.getAbsolutePath());
Log.i(TAG, "dest path: " + dest.getAbsolutePath());
try {
inChannel = new FileInputStream(source).getChannel();
outChannel = new FileOutputStream(dest).getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
} catch (IOException e) {
e.printStackTrace();
}
}
解決方案:
及時關(guān)閉IO流,避免泄露
public static void copyFile(File source, File dest) {
FileChannel inChannel = null;
FileChannel outChannel = null;
Log.i(TAG, "source path: " + source.getAbsolutePath());
Log.i(TAG, "dest path: " + dest.getAbsolutePath());
try {
inChannel = new FileInputStream(source).getChannel();
outChannel = new FileOutputStream(dest).getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inChannel != null) {
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outChannel != null) {
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
E/StrictMode: A resource was acquired at attached stack trace but never released.
See java.io.Closeable for information on avoiding resource leaks.
java.lang.Throwable: Explicit termination method 'close' not called
at dalvik.system.CloseGuard.open(CloseGuard.java:180)
at java.io.FileOutputStream.<init>(FileOutputStream.java:89)
at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
at com.heyniu.lock.utils.FileUtil.copyFile(FileUtil.java:44)
at com.heyniu.lock.db.BackupData.backupData(BackupData.java:89)
at com.heyniu.lock.ui.HomeActivity$11.onClick(HomeActivity.java:675)
at android.support.v7.app.AlertController$ButtonHandler.handleMessage(AlertController.java:157)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
單例模式泄露
分析:通過截圖我們發(fā)現(xiàn)SplashActivity被ActivityUtil的實例activityStack持有
引用代碼:
ActivityUtil.getAppManager().add(this);
持有代碼:
public void add(Activity activity) {
if (activityStack == null) {
synchronized (ActivityUtil.class){
if (activityStack == null) {
activityStack = new Stack<>();
}
}
}
activityStack.add(activity);
}
解決方案:
在SplashActivity的onDestroy()生命周期移除引用
@Override
protected void onDestroy() {
super.onDestroy();
ActivityUtil.getAppManager().remove(this);
}
靜態(tài)變量持有Context實例泄露
分析:長生命周期持有短什么周期引用導(dǎo)致泄露,詳見上文四大組件Context和Application的context使用
示例引用代碼:
private static HttpRequest req;
public static void HttpUtilPost(Context context, int TaskId, String url, String requestBody,ArrayList<HttpHeader> Headers, RequestListener listener) {
// TODO Auto-generated constructor stub
req = new HttpRequest(context, url, TaskId, requestBody, Headers, listener);
req.post();
}
解決方案:
public static void cancel(int TaskId) {
if(req != null && req.get() != null){
req.get().AsyncCancel(TaskId);
}
}
private static WeakReference<HttpRequest> req;
public static void HttpUtilPost(Context context, int TaskId, String url, String requestBody,ArrayList<HttpHeader> Headers, RequestListener listener) {
// TODO Auto-generated constructor stub
req = new WeakReference<HttpRequest>(new HttpRequest(context, url, TaskId, requestBody, Headers, listener));
req.get().post();
}
private static HttpRequest req;
public static void HttpUtilPost(Context context, int TaskId, String url, String requestBody,ArrayList<HttpHeader> Headers, RequestListener listener) {
// TODO Auto-generated constructor stub
req = new HttpRequest(context.getApplicationContext(), url, TaskId, requestBody, Headers, listener);
req.post();
}
改為長生命周期
改為弱引用
pass:弱引用隨時可能為空,使用前先判空
示例代碼:
Context泄露
Callback泄露
服務(wù)未解綁注冊泄露
分析:一般發(fā)生在注冊了某服務(wù),不用時未解綁服務(wù)導(dǎo)致泄露
引用代碼:
private void initSensor() {
// 獲取傳感器管理器
sm = (SensorManager) container.activity.getSystemService(Context.SENSOR_SERVICE);
// 獲取距離傳感器
acceleromererSensor = sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);
// 設(shè)置傳感器監(jiān)聽器
acceleromererListener = new SensorEventListener() {
......
};
sm.registerListener(acceleromererListener, acceleromererSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
解決方案:
在Activity的onDestroy()方法解綁服務(wù)
@Override
protected void onDestroy() {
super.onDestroy();
sm.unregisterListener(acceleromererListener,acceleromererSensor);
}
Handler泄露
分析:由于Activity已經(jīng)關(guān)閉,Handler任務(wù)還未執(zhí)行完成,其引用了Activity的實例導(dǎo)致內(nèi)存泄露
引用代碼:
handler.sendEmptyMessage(0);
解決方案:
在Activity的onDestroy()方法回收Handler
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
圖片后續(xù)遇到再補(bǔ)上
異步線程泄露
分析:一般發(fā)生在線程執(zhí)行耗時操作時,如下載,此時Activity關(guān)閉后,由于其被異步線程引用,導(dǎo)致無法被正?;厥眨瑥亩鴥?nèi)存泄露
引用代碼:
new Thread() {
public void run() {
imageArray = loadImageFromUrl(imageUrl);
}.start();
解決方案:
把線程作為對象提取出來
在Activity的onDestroy()方法阻塞線程
thread = new Thread() {
public void run() {
imageArray = loadImageFromUrl(imageUrl);
};
thread.start();
@Override
protected void onDestroy() {
super.onDestroy();
if(thread != null){
thread.interrupt();
thread = null;
}
}
后面
歡迎補(bǔ)充實際中遇到的泄露類型
文章如有錯誤,歡迎指正
如有更好的內(nèi)存泄露分享方法,歡迎一起討論
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android開發(fā)常見內(nèi)存泄漏和相應(yīng)的對策(二)
Android Service服務(wù)(二) BroadcastReceiver
Android Service 服務(wù)(一)
WebView 想說愛你不容易啊
android service 學(xué)習(xí)(上)
android生命周期
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服