日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Android內(nèi)存性能優(yōu)化

 老匹夫 2014-09-17
Android內(nèi)存性能優(yōu)化(內(nèi)部資料總結(jié))
2014-05-23     我來(lái)說(shuō)兩句    來(lái)源:Android內(nèi)存性能優(yōu)化(內(nèi)部資料總結(jié))  
收藏    我要投稿

剛?cè)腴T(mén)的童鞋肯能都會(huì)有一個(gè)疑問(wèn),Java不是有虛擬機(jī)了么,內(nèi)存會(huì)自動(dòng)化管理,我們就不必要手動(dòng)的釋放資源了,反正系統(tǒng)會(huì)給我們完成。其實(shí)Java中沒(méi)有指針的概念,但是指針的使用方式依然存在,一味的依賴(lài)系統(tǒng)的gc,很容易就造成了內(nèi)存的浪費(fèi)。

Java基于垃圾回收的內(nèi)存機(jī)制

Java的內(nèi)存管理機(jī)制會(huì)自動(dòng)回收無(wú)用對(duì)象所占用的內(nèi)存,減輕手工管理內(nèi)存的負(fù)擔(dān)

1、C/C++: 從申請(qǐng)、使用、釋放都需要手工管理

2、Java:無(wú)用的對(duì)象的內(nèi)存會(huì)被自動(dòng)回收

\



什么樣的對(duì)象是無(wú)用的對(duì)象

1、Java通過(guò)引用來(lái)操作一個(gè)具體的對(duì)象,引用類(lèi)似于C 中的指針。一個(gè)對(duì)象可以持有其他對(duì)象的引用。

2、從一組根對(duì)象(GC Roots)開(kāi)始,按對(duì)象之前的引用關(guān)系遍歷所有對(duì)象,在遍歷過(guò)程中標(biāo)記所有的可達(dá)對(duì)象。如果一個(gè)對(duì)象由根對(duì)象出發(fā)不可達(dá),則將它作為垃圾收集。

GCRoot 都有哪些?

1、 Class:由系統(tǒng)的類(lèi)加載器加載的類(lèi)對(duì)象

2、 Static Fields

3、 Thread:活著的線程

4、 Stack Local: java方法的局部變量或參數(shù)

5、 JNI Local: JNI方法中的局部引用

6、 JNI Global: 全局的JNI引用

7、 Monitor used: 用于同步的監(jiān)控對(duì)象

8、Help by VM: 用于JVM特殊目的由GC保留的對(duì)象

\\\


Java程序中的內(nèi)存泄漏

對(duì)象的內(nèi)存在分配之后無(wú)法通過(guò)程序的執(zhí)行邏輯釋放對(duì)該對(duì)象的引用,不能被回收該對(duì)象所占內(nèi)存

內(nèi)存泄漏的危害

1、 引起OutOfMemoryError

2、 內(nèi)存占用高時(shí)JVM虛擬機(jī)會(huì)頻繁觸發(fā)GC, 影響程序響應(yīng)速度

3、內(nèi)存占用大的程序容易被各種清理優(yōu)化程序中止,用戶也更傾向于卸載這些程序

Android應(yīng)用的開(kāi)發(fā)語(yǔ)言為Java,每個(gè)應(yīng)用最大可使用的堆內(nèi)存受到Android系統(tǒng)的限制

Android每一個(gè)應(yīng)用的堆內(nèi)存大小有限

1、 通常的情況為16M-48M

2、 通過(guò)ActivityManager的getMemoryClass()來(lái)查詢可用堆內(nèi)存限制

3、3.0(HoneyComb)以上的版本可以通過(guò)largeHeap=“true”來(lái)申請(qǐng)更多的堆內(nèi)存

Nexus S(4.2.1):normal 192, largeHeap 512

4、如果試圖申請(qǐng)的內(nèi)存大于當(dāng)前余下的堆內(nèi)存就會(huì)引發(fā)OutOfMemoryError()

5、應(yīng)用程序由于各方面的限制,需要注意減少內(nèi)存占用,避免出現(xiàn)內(nèi)存泄漏。

用MAT工具來(lái)檢測(cè)內(nèi)存泄漏

在試圖窗口中新建一個(gè)Memory Analysis會(huì)出現(xiàn)一個(gè)

\

沒(méi)有的可以去http://www./mat/downloads.php安裝一下MAT

在Android 的調(diào)試環(huán)境DDMS下,找到Heap dump

\\

Dump下當(dāng)前內(nèi)存中的鏡像文件,*****.hprof

\

能清楚的看到每一個(gè)部分暫用的內(nèi)存大小。

也可以切換試圖,group查看不同包不同類(lèi)的占用細(xì)節(jié)。

\

Heap dump

包含了觸發(fā)Heap dump生成的時(shí)刻Java進(jìn)程的內(nèi)存快照,主要內(nèi)容為各個(gè)Java類(lèi)和對(duì)象在堆內(nèi)存中的分配情況

Memory Analyzer Tool (MAT)

常見(jiàn)內(nèi)存泄露原因

Context對(duì)象泄漏

1、如果一個(gè)類(lèi)持有Context對(duì)象的強(qiáng)引用,就需要檢查其生存周期是否比Context對(duì)象更長(zhǎng)。否則就可能發(fā)生Context泄漏。

2、View持有其創(chuàng)建所在Context對(duì)象的引用,如果將View對(duì)象傳遞給其它生存周期比View所在Context更長(zhǎng)的強(qiáng)引用,就可能會(huì)引起內(nèi)存泄漏。

例如View#setTag(int, Object)的內(nèi)存泄漏https://code.google.com/p/android/issues/detail?id=18273

3、把Context對(duì)象賦給static變量。

避免Context對(duì)象泄漏Checklist

1、檢查所有持有對(duì)Context對(duì)象強(qiáng)引用的對(duì)象的生命周期是否超出其所持有的Context對(duì)象的生命周期。

2、檢查有沒(méi)有把View傳出到View所在Context之外的地方,如果有的話就需要檢查生命周期。

3、工具類(lèi)中最好不要有Context成員變量,盡量在調(diào)用函數(shù)時(shí)直接通過(guò)調(diào)用參數(shù)傳入。如果必須有Context成員變量時(shí),可以考慮使用WeakReference來(lái)引用Context對(duì)象。

4、View持有其創(chuàng)建所在Context對(duì)象的引用,如果將View對(duì)象傳遞給其它生存周期比View所在Context更長(zhǎng)的強(qiáng)引用,就可能會(huì)引起內(nèi)存泄漏。

5、 檢查把Context或者View對(duì)象賦給static變量的地方,看是否有Context泄漏。

6、檢查所有把View放入容器類(lèi)的地方(特別是static容器類(lèi)),看是否有內(nèi)存泄漏。7、使用WeakHashMap也需要注意有沒(méi)有value-key的引用。

7、盡量使用ApplicationContext。

Handler對(duì)象泄漏

1、發(fā)送到Handler的Message實(shí)際上是加入到了主線程的消息隊(duì)列等待處理,每一個(gè)Message持有其目標(biāo)Handler的強(qiáng)引用。

如我們通常使用的匿名內(nèi)部類(lèi)Handler

1
2
3
4
5
6
<span style="font-size:18px;">HandlermHandler = new Handler() {
    @Override
    public voidhandleMessage(Message msg) {
       mImageView.setImageBitmap(mBitmap);
    }
}</span>


上面是一段簡(jiǎn)單的Handler的使用。當(dāng)使用內(nèi)部類(lèi)(包括匿名類(lèi))來(lái)創(chuàng)建Handler的時(shí)候,Handler對(duì)象會(huì)隱式地持有一個(gè)外部類(lèi)對(duì)象(通常是一個(gè)Activity)的引用,因?yàn)閂iew會(huì)依附著一個(gè)Activity。而Handler通常會(huì)伴隨著一個(gè)耗時(shí)的后臺(tái)線程(例如從網(wǎng)絡(luò)拉取圖片)一起出現(xiàn),這個(gè)后臺(tái)線程在任務(wù)執(zhí)行完畢(例如圖片下載完畢)之后,通過(guò)消息機(jī)制通知Handler,然后Handler把圖片更新到界面。然而,如果用戶在網(wǎng)絡(luò)請(qǐng)求過(guò)程中關(guān)閉了Activity,正常情況下,Activity不再被使用,它就有可能在GC檢查時(shí)被回收掉,但由于這時(shí)線程尚未執(zhí)行完,而該線程持有Handler的引用(不然它怎么發(fā)消息給Handler?),這個(gè)Handler又持有Activity的引用,就導(dǎo)致該Activity無(wú)法被回收(即內(nèi)存泄露),直到網(wǎng)絡(luò)請(qǐng)求結(jié)束(例如圖片下載完畢)。另外,如果你執(zhí)行了Handler的postDelayed()方法,該方法會(huì)將你的Handler裝入一個(gè)Message,并把這條Message推到MessageQueue中,那么在你設(shè)定的delay到達(dá)之前,會(huì)有一條MessageQueue -> Message -> Handler -> Activity的鏈,導(dǎo)致你的Activity被持有引用而無(wú)法被回收。

當(dāng)然,應(yīng)為是Handler對(duì)外部持有引用的原因,我們就可以將Activity設(shè)置為一個(gè)弱引用,在不必要的時(shí)候,不再執(zhí)行內(nèi)部方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<span style="font-size:18px;">/**
 * @author zhoushengtao
 * @since 2013-12-16 下午3:25:36
 */
  
import android.app.Activity;
importandroid.content.Context;
importandroid.os.Handler;
importandroid.os.Message;
  
importjava.lang.ref.WeakReference;
  
publicclass WeakRefHandler extends Handler
{
    WeakReference<context> mWeakContext;
  
    public WeakRefHandler(Context context)
    {
        mWeakContext = newWeakReference<context>(context);
    }
  
    @Override
    public void handleMessage(Message msg)
    {
        if((mWeakContext.get() instanceofActivity )&& ((Activity)mWeakContext.get()).isFinishing())
                return ;
        if(mWeakContext==null){
            return ;
        }
        super.handleMessage(msg);
    }
}</context></context></span>


2、Non-staticinner class 和anonymous class持有其outer class的引用。

Drawable.Callback引起的內(nèi)存泄漏

Drawable對(duì)象持有Drawable.callback的引用。當(dāng)把一個(gè)Drawable對(duì)象設(shè)置到一個(gè)View時(shí),Drawable對(duì)象會(huì)持有該View的引用作為Drawable.Callback

\


避免Drawable.Callback引起內(nèi)存泄漏

盡量不要在static成員中保存Drawable對(duì)象

對(duì)于需要保存的Drawable對(duì)象, 在需要時(shí)調(diào)用Drawable#setCallback(null).

\

其他內(nèi)存泄漏<喎?"http://www./kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4KPHAgYWxpZ249"left"> 1、Android DigitalClock引起的內(nèi)存泄漏http://code.google.com/p/android/issues/detail?id=17015

2、使用Map容器類(lèi)時(shí),作為Key 的類(lèi)沒(méi)有正確的實(shí)現(xiàn)hashCode和equal函數(shù)

其他內(nèi)存泄漏

JNI程序中的內(nèi)存泄漏

1、 Malloc/free。

2、 JNI Global reference

Thread-Local Variable

1、 相當(dāng)于Thread對(duì)象的成員變量, 可以存儲(chǔ)線程相關(guān)的狀態(tài)

2、 如果thread是alive狀態(tài),那么Thread-Local中的對(duì)象就無(wú)法被GC。

進(jìn)程內(nèi)存占用監(jiān)測(cè)工具

Dumpsys

$ dumpsys meminfo [pid]

\

Procrank + Shell腳本

#procrank

1、 VSS - Virtual Set Size 虛擬耗用內(nèi)存(包含共享庫(kù)占用的內(nèi)存)

2、 RSS - Resident Set Size 實(shí)際使用物理內(nèi)存(包含共享庫(kù)占用的內(nèi)存)

3、 PSS - Proportional Set Size 實(shí)際使用的物理內(nèi)存(比例分配共享庫(kù)占用的內(nèi)存)

4、 USS - Unique Set Size 進(jìn)程獨(dú)自占用的物理內(nèi)存(不包含共享庫(kù)占用的內(nèi)存)

\

Shell腳本

#!/bin/bash

while true; do

adbshell procrank " grep "com.qihoo360.mobilesafe"

sleep1

done

當(dāng)然,部分機(jī)型的sh都是經(jīng)過(guò)第三方手機(jī)商精簡(jiǎn)過(guò)的,很多命令都用不了。Procrank,就是一個(gè)經(jīng)常被精簡(jiǎn)掉的命令。

鑒于此:

自己寫(xiě)了一個(gè)小工具,檢測(cè)內(nèi)存的實(shí)時(shí)變化,

Github地址:https://github.com/stchou/JasonTest

\\

小結(jié)

1. 保存對(duì)象前要三思

I. 對(duì)象本身有無(wú)隱含的引用

II. 保存后何時(shí)能夠回收

2. 要了解常見(jiàn)的隱含引用

I. anonymous class outer class

II. View to context

3. 要通過(guò)各種工具檢查內(nèi)存占用是否有異常

4. 創(chuàng)建大對(duì)象時(shí),要檢查它的生命周期


/**
* @author zhoushengtao(周圣韜)
* @since 2014年5月21日 下午6:18:29

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多