移動(dòng)開發(fā)的內(nèi)存管理

移動(dòng)系統(tǒng)對(duì)資源的限制和要求

移動(dòng)操作系統(tǒng)現(xiàn)對(duì)于PC端的一個(gè)首要特點(diǎn)就是資源有限,比如內(nèi)存、電池嘲碱、網(wǎng)絡(luò)的不確定等等,這些資源相對(duì)于PC端來(lái)說(shuō)都很有限局蚀,當(dāng)然對(duì)于發(fā)展到今天的移動(dòng)端設(shè)備來(lái)說(shuō)麦锯,這個(gè)已經(jīng)不算是一個(gè)大問題了,不過琅绅,在移動(dòng)端開發(fā)中扶欣,針對(duì)資源有限的問題都是一個(gè)不得不正視的問題。本文主要針對(duì)內(nèi)存這一塊進(jìn)行闡述,針對(duì)移動(dòng)網(wǎng)絡(luò)的特點(diǎn)料祠、電池優(yōu)化的問題骆捧、有后續(xù)系列闡述文章。

移動(dòng)操作系統(tǒng)的幾個(gè)主要特點(diǎn)

  • 移動(dòng)設(shè)備需要便攜髓绽,所以需要攜帶電池敛苇,需要專門的電池管理,這一點(diǎn)顺呕,筆者當(dāng)年首次學(xué)習(xí)Symbian系統(tǒng)時(shí)卻有體會(huì)枫攀;
  • 移動(dòng)設(shè)備通常情況下,屏幕比較小株茶,但是需要展示的信息一點(diǎn)也不少来涨,所以,就需要在界面設(shè)計(jì)以及交互設(shè)計(jì)上(UI UE)需要更多的想象力启盛,需要更好的更人性化的設(shè)計(jì)蹦掐,需要面對(duì)的情況也更復(fù)雜;
  • 由于移動(dòng)設(shè)備的大部分都需要電池供電僵闯,所以卧抗,在選擇CPU時(shí),也就必須考慮好CPU的功耗問題鳖粟,復(fù)雜指令集的基本不建議在考慮之列颗味。
  • 同樣由于電池所限,使用的內(nèi)存(memory)和存儲(chǔ)相對(duì)于PC桌面系統(tǒng)來(lái)說(shuō)都相當(dāng)受限制牺弹。
  • 由于移動(dòng)設(shè)備資源所限浦马,大部分移動(dòng)設(shè)備操作系統(tǒng),都需要分時(shí)復(fù)用來(lái)管理所有的需要運(yùn)行的程序(通常叫App)张漂。
    • 現(xiàn)階段流行的移動(dòng)操作系統(tǒng)主要是ios和android晶默,其中大部分程序都運(yùn)行在后臺(tái)情況下,都由系統(tǒng)層面管理App所占用的各類資源航攒,比如內(nèi)存磺陡,當(dāng)程序后臺(tái)運(yùn)行時(shí),大部分情況下內(nèi)存都會(huì)被回收漠畜。
    • 移動(dòng)操作系統(tǒng)一般情況下都會(huì)限制每個(gè)應(yīng)用所消耗的資源總量币他。
    • 作為App開發(fā)者,管理好自身App所消耗的資源是一個(gè)應(yīng)盡的義務(wù)憔狞。
  • 管理

Android內(nèi)存管理機(jī)制淺析

Android是2007年Google在收購(gòu)基礎(chǔ)上推出的基于Linux操作系統(tǒng)的開源移動(dòng)操作系統(tǒng)蝴悉,該平臺(tái)由操作系統(tǒng)、中間件瘾敢、用戶界面和應(yīng)用軟件組成拍冠。

Android的系統(tǒng)架構(gòu)和其操作系統(tǒng)一樣尿这,采用了分層的架構(gòu)。[
Android結(jié)構(gòu)

Android結(jié)構(gòu)

從架構(gòu)圖看庆杜,Android分為四個(gè)層射众,分別是應(yīng)用程序?qū)印?yīng)用程序框架層晃财、系統(tǒng)運(yùn)行庫(kù)層和Linux層叨橱。

Android應(yīng)用開發(fā)

在Android平臺(tái)上開發(fā)應(yīng)用程序,包括java 和C++(for Native)断盛。

android平臺(tái)的內(nèi)存管理

一般情況下(多進(jìn)程例外)每個(gè)應(yīng)用都會(huì)由系統(tǒng)分配一個(gè)進(jìn)程(zygote)資源雏逾。這段Android代碼可以獲取當(dāng)前進(jìn)程的內(nèi)存情況。

        ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
        int memClass = activityManager.getMemoryClass();
        int maxClass = activityManager.getLargeMemoryClass();

任何一個(gè)進(jìn)程最多可以獲取的內(nèi)存資源時(shí)有限的郑临。

內(nèi)存優(yōu)化思路

強(qiáng)引用與弱引用

  • 在一個(gè)Activity生命周期中,其中所有定義的變量的生命周期都和Activty保持一致屑宠,如果用強(qiáng)引用的話厢洞,那么變量所指向的內(nèi)存和Activity生命周期保持一致,但是在很多情況下典奉,從邏輯上這個(gè)成員變量已經(jīng)不需要了躺翻,由于強(qiáng)引用其所指向的內(nèi)存區(qū)域也保持一樣的什么周期,有點(diǎn)得不償失卫玖。
  • 這種情況下公你,可以選擇弱引用,所謂弱引用就是指其指向的內(nèi)存區(qū)域假瞬,在內(nèi)存比較緊張的時(shí)候可以被GC陕靠。這樣就可以減少內(nèi)存的使用。
    WeakReference<ForeEngine> mWeakForeEngine;
    ForeEngine  mForeEngine;

其中:

  • mForeEngine是強(qiáng)引用脱茉,mWeakForeEngine是弱引用
  • mWeakForeEngine指向的內(nèi)存在mWeakForeEngine運(yùn)行過程中可能會(huì)被回收

弱引用的初始化

     mWeakForeEngine  = new WeakReference<ForeEngine>(foreEngine) ;

弱引用的使用

      ForeEngine foreEngine = mWeakForeEngine.get();
     if(foreEngine == null) {
     //  todo
     }

關(guān)注內(nèi)存大戶Bitmap

待續(xù)

Android內(nèi)存管理原理簡(jiǎn)析

Java虛擬機(jī)模型

JVM內(nèi)存模型剪芥,java虛擬機(jī)在構(gòu)建RunTime運(yùn)行時(shí)數(shù)據(jù)內(nèi)存分配,
內(nèi)存主要分為方法區(qū)琴许,虛擬機(jī)棧税肪,本地方法棧,堆榜田,PCR程序計(jì)數(shù)器益兄。

JVM內(nèi)存模型示意

Android的改進(jìn)

- 寄存器和棧的區(qū)別
     * JVM虛擬機(jī)基于棧,DVM基于寄存器箭券。*
- Dalvik和java虛擬的區(qū)別  dex class的區(qū)別
-  dalvik art的改進(jìn)
   android虛擬機(jī)都使用頁(yè)式和memory mapping方式進(jìn)行內(nèi)存管理净捅,虛擬機(jī)分配并決定了內(nèi)存的生命周期,并且使用GC(*garbage collection*)來(lái)回收已分配但是不再使用的內(nèi)存片段辩块,GC的主要工作主要分為兩個(gè)部分:
     1)找到內(nèi)存中不再使用的數(shù)據(jù)片段
     2)回收這些資源
   分配內(nèi)存資源主要是分代管理灸叼,剛剛分配的內(nèi)存區(qū)域叫Young Generation神汹。
   對(duì)象在Young Generation時(shí)間比較長(zhǎng)之后,就會(huì)被劃到Older Generation古今,還有一個(gè)permanent generation屁魏。
    盡管內(nèi)存回收的速度較快,但是由于會(huì)在程序運(yùn)行過程中的停下執(zhí)行GC捉腥,不可避免的的會(huì)影響程序的運(yùn)行氓拼,一旦GC邊界條件被觸發(fā),系統(tǒng)就會(huì)停止當(dāng)前進(jìn)程抵碟,開始GC桃漾。
    關(guān)于GC的詳細(xì)機(jī)制詳見,ref:
- Android Runtime(ART)的進(jìn)一步改進(jìn)措施
    1) ART中暫停次數(shù)相比于Dalvik有減少拟逮,從兩次減為一次;
    2)ART GC 一樣有暫停中斷撬统,不一樣之處在于,ART在有些階段比如引用過程敦迄,sytem sweeping過程恋追,等階段中可以并發(fā)的執(zhí)行GC。

DVM算法簡(jiǎn)析

  • 程序運(yùn)行過程中罚屋,不斷申請(qǐng)新的對(duì)象消耗內(nèi)存苦囱,直到用完所有,然后創(chuàng)建新的對(duì)象需要內(nèi)存的時(shí)候脾猛,暫停運(yùn)行撕彤,出發(fā)GC 回收,器原理就是從GC Roots開始猛拴,將整個(gè)內(nèi)存遍歷羹铅,保留所有被直接以及間接用的內(nèi)存區(qū)域,余下的被回收愉昆。
    該算法可以解決內(nèi)存的問題睦裳,釋放內(nèi)存。
  • 但是缺點(diǎn)一樣存在撼唾,1 從GC Roots開始的遍歷是一個(gè)遞歸調(diào)用廉邑,這個(gè)過程本身會(huì)消耗很多資源,一方面在內(nèi)存不多時(shí)候消耗內(nèi)存遞歸倒谷,另一方面蛛蒙,如果遍歷非常深的話,消耗的時(shí)間資源也很明顯渤愁。所有后來(lái)的android系統(tǒng)優(yōu)化了這個(gè)過程牵祟,另開啟線程逐步釋放內(nèi)存,盡量不影響程序的正常運(yùn)行抖格。也就是逐步GC诺苹,還有一個(gè)叫CMS(concurrent mark sweep)咕晋。
  • 下面是代碼

    1 啟動(dòng)VM

\dalvik\vm\Init.cpp
/*
* VM initialization.  Pass in any options provided on the command line.
* Do not pass in the class name or the options for the class.
*
* Returns 0 on success.
*/
std::string dvmStartup(int argc, const char* const argv[],
bool ignoreUnrecognized, JNIEnv* pEnv)

其中 啟動(dòng)的內(nèi)容很多,有興趣的可以參考源代碼。

2 GC 啟動(dòng)

在main heap上采用mmap管理內(nèi)存。
dalvik\vm\alloc\alloc.cpp

/*
* Initialize the GC universe.
*
* We're currently using a memory-mapped arena to keep things off of the
* main heap.  This needs to be replaced with something real.
*/
bool dvmGcStartup()
{
dvmInitMutex(&gDvm.gcHeapLock);
pthread_cond_init(&gDvm.gcHeapCond, NULL);
return dvmHeapStartup();
}

3 GC heap啟動(dòng)

dalvik\vm\alloc\Heap.cpp
初始化GC heap 并建立VM card table锋谐。

/*
* Initialize the GC heap.
*
* Returns true if successful, false otherwise.
*/
bool dvmHeapStartup()
{
GcHeap *gcHeap;
if (gDvm.heapGrowthLimit == 0) {
gDvm.heapGrowthLimit = gDvm.heapMaximumSize;
}
gcHeap = dvmHeapSourceStartup(gDvm.heapStartingSize,
gDvm.heapMaximumSize,
gDvm.heapGrowthLimit);
if (gcHeap == NULL) {
return false;
}
gcHeap->ddmHpifWhen = 0;
gcHeap->ddmHpsgWhen = 0;
gcHeap->ddmHpsgWhat = 0;
gcHeap->ddmNhsgWhen = 0;
gcHeap->ddmNhsgWhat = 0;
gDvm.gcHeap = gcHeap;
/* Set up the lists we'll use for cleared reference objects.
*/
gcHeap->clearedReferences = NULL;
if (!dvmCardTableStartup(gDvm.heapMaximumSize, gDvm.heapGrowthLimit)) {
LOGE_HEAP("card table startup failed.");
return false;
}
return true;
}

4

dalvik\vm\alloc\HeapSource.cpp
為了不和zygote heap的內(nèi)存發(fā)生交集,在首次fork之前調(diào)用它质蕉,這個(gè)仍然會(huì)有一些造成小片段內(nèi)存的問題存在

/*
* This is called while in zygote mode, right before we fork() for the
* first time.  We create a heap for all future zygote process allocations,
* in an attempt to avoid touching pages in the zygote heap.  (This would
* probably be unnecessary if we had a compacting GC -- the source of our
* troubles is small allocations filling in the gaps from larger ones.)
*/
bool dvmHeapSourceStartupBeforeFork()
{
HeapSource *hs = gHs; // use a local to avoid the implicit "volatile"
HS_BOILERPLATE();
assert(gDvm.zygote);
if (!gDvm.newZygoteHeapAllocated) {
/* Ensure heaps are trimmed to minimize footprint pre-fork.
*/
trimHeaps();
/* Create a new heap for post-fork zygote allocations.  We only
* try once, even if it fails.
*/
ALOGV("Splitting out new zygote heap");
gDvm.newZygoteHeapAllocated = true;
return addNewHeap(hs);
}
return true;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市翩肌,隨后出現(xiàn)的幾起案子模暗,更是在濱河造成了極大的恐慌,老刑警劉巖念祭,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兑宇,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡粱坤,警方通過查閱死者的電腦和手機(jī)隶糕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)比规,“玉大人,你說(shuō)我怎么就攤上這事拦英⊙咽玻” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵疤估,是天一觀的道長(zhǎng)灾常。 經(jīng)常有香客問我,道長(zhǎng)铃拇,這世上最難降的妖魔是什么钞瀑? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮慷荔,結(jié)果婚禮上雕什,老公的妹妹穿的比我還像新娘。我一直安慰自己显晶,他們只是感情好贷岸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著磷雇,像睡著了一般偿警。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上唯笙,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天螟蒸,我揣著相機(jī)與錄音盒使,去河邊找鬼。 笑死七嫌,一個(gè)胖子當(dāng)著我的面吹牛少办,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抄瑟,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼凡泣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了皮假?” 一聲冷哼從身側(cè)響起鞋拟,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惹资,沒想到半個(gè)月后贺纲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡褪测,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年猴誊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侮措。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡懈叹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出分扎,到底是詐尸還是另有隱情澄成,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布畏吓,位于F島的核電站墨状,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏菲饼。R本人自食惡果不足惜肾砂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望宏悦。 院中可真熱鬧镐确,春花似錦、人聲如沸饼煞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)派哲。三九已至臼氨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芭届,已是汗流浹背储矩。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工感耙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人持隧。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓即硼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親屡拨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子只酥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容