版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
Android內(nèi)存管理認識目錄LowMemoryKillerAshmemPmemdalvik虛擬機內(nèi)存管理低內(nèi)存管理器(LowMemoryKiller)低內(nèi)存管理器(LowMemoryKiller),相對于Linux標準OOM(OutOfMemory)機制更加靈活,它可以根據(jù)需要殺死進程來釋放需要的內(nèi)存。源代碼位于drivers/staging/Android/lowmemorykiller.c匿名共享內(nèi)存(ashmem),為進程間提供大塊共享內(nèi)存,同時為內(nèi)核提供回收和管理這個內(nèi)存的機制。源代碼位于mm/ashmem.cAndroidPMEM(Physical),PMEM用于向用戶空間提供連續(xù)的物理內(nèi)存區(qū)域,DSP和某些設(shè)備只能工作在連續(xù)的物理內(nèi)存上。源代碼位于drivers/misc/pmem.c
LowMemoryKiller的實現(xiàn)
LowMemoryKiller的源代碼在drivers/staging/android/lowmemorykiller.c中,它是通過注冊CacheShrinker來實現(xiàn)的。CacheShrinker是標準linuxkernel回收內(nèi)存頁面的一種機制,它由內(nèi)核線程kswapd監(jiān)控,當空閑內(nèi)存頁面不足時,kswapd會調(diào)用注冊的Shrinker回調(diào)函數(shù),來回收內(nèi)存頁面。LowMemoryKiller是在模塊初始化時注冊CacheShrinker的,代碼如下:staticint__initlowmem_init(void){register_shrinker(&lowmem_shrinker);//注冊CacheShrinkerreturn0;} lowmem_shrinker的定義如下:staticstructshrinkerlowmem_shrinker={.shrink=lowmem_shrink,.seeks=DEFAULT_SEEKS*16}; register_shrinker會將lowmem_shrink加入ShrinkerList中,被kswapd在遍歷ShrinkerList時調(diào)用,而LowMemoryKiller的功能就是在lowmem_shrink中實現(xiàn)的。
lowmem_shrink用兩個數(shù)組作為選擇Bad進程的依據(jù),這兩個數(shù)組的定義如下:
staticintlowmem_adj[6]={
0,
1,
6,
12,
};
staticintlowmem_adj_size=4;
staticsize_tlowmem_minfree[6]={
3*512,//6MB
2*1024,//8MB
4*1024,//16MB
16*1024,//64MB
};
lowmem_shrink首先計算當前空閑內(nèi)存的大小,如果小于某個閾值,則以該閾值對應的優(yōu)先級為基準,遍歷各個進程,計算每個進程占用內(nèi)存的大小,找出優(yōu)先級大于基準優(yōu)先級的進程,在這些進程中選擇優(yōu)先級最大的殺死,如果優(yōu)先級相同,則選擇占用內(nèi)存最多的進程。
lowmem_shrink殺死進程的方法是向進程發(fā)送一個不可以忽略或阻塞的SIGKILL信號:
force_sig(SIGKILL,selected);
用戶接口
設(shè)置空閑內(nèi)存閾值的接口:/sys/module/lowmemorykiller/parameters/minfree,設(shè)置對應優(yōu)先級的接口:/sys/module/lowmemorykiller/parameters/adj,設(shè)置各個進程優(yōu)先級的接口:/proc/<進程pid>/oom_adj。Android啟動時讀取的配置文件/init.rc中定義了相應的屬性供AP使用并有設(shè)置這些參數(shù)。將init進程oom_adj設(shè)置為-16,從而保證init進程永遠不會被殺掉。Ashmem的基本結(jié)構(gòu)主要函數(shù)功能簡單分析
ashmem_init這是module初始化函數(shù),Ashmem是作為一個模塊實現(xiàn)的。該函數(shù)主要功能:調(diào)用kmem_cache_create分別創(chuàng)建structashmem_area和structashmem_range的slabcache
調(diào)用misc_register注冊ahsmemdriver
調(diào)用register_shrinker注冊Ashmem的CacheShrinkerashmem_open標準misc設(shè)備的open函數(shù)。它調(diào)用kmem_cache_zalloc分配一個ashmem_area,并初始化各成員變量。
ashmem_release做與ashmem_open相反工作,釋放tmpfs文件,ashmem_area及其ashmem_range。
ashmem_mmapmmap操作,主要就是調(diào)用shmem_file_setup從tmpfs文件系統(tǒng)中創(chuàng)建一個文件(實際上就是一段RAM)給ashmem_area用,該文件代表著這段被共享的內(nèi)存。Ashmem真正實現(xiàn)進程共享內(nèi)存的機制是靠shmem這個linux標準機制提供的。
主要函數(shù)功能簡單分析ashmem_shrink即Ashmem的cacheshrink函數(shù)。它被mm/vmscan.c::shrink_slab調(diào)用,或者被用戶的ioctl命令調(diào)用。這個函數(shù)從LRU鏈表上回收指定數(shù)目的unpinnedashmem_range。
ashmem_ioctl這個函數(shù)提供ioctl接口,它實現(xiàn)了如下命令:主要函數(shù)功能簡單分析ashmem_unpinunpin一段內(nèi)存。實現(xiàn)的方法很簡單,就是分配一個ashmem_range,把它掛到ashmem_area->unpinned_list上,并加到LRU鏈表上。ashmem_pinpin一段內(nèi)存,從ashmem_area->unpinned_list上拿下這個ashmem_range,由此可知,被unpin的range才能被回收,pin的range則不能回收。用戶接口Ashmem驅(qū)動創(chuàng)建了/dev/ashmem設(shè)備文件,進程A可通過open打開該文件,用ioctl命令ASHMEM_SET_NAME和ASHMEM_SET_SIZE設(shè)置共享內(nèi)存塊的名字和大小,并將得到的handle傳給mmap,來獲得共享的內(nèi)存區(qū)域,進程B通過將相同的handle傳給mmap,獲得同一塊內(nèi)存,handle在進程間的傳遞可通過Binder來實現(xiàn)。Pmem相關(guān)介紹基本原理AndroidPmem是為了實現(xiàn)共享大尺寸連續(xù)物理內(nèi)存而開發(fā)的一種機制,該機制對dsp,gpu等部件非常有用。Pmem相當于把系統(tǒng)內(nèi)存劃分出一部分單獨管理,即不被linuxmm管理,實際上linuxmm根本看不到這段內(nèi)存。Pmem與Ashmem的區(qū)別Pmem和Ashmem都通過mmap來實現(xiàn)共享內(nèi)存,其區(qū)別在于Pmem的共享區(qū)域是一段連續(xù)的物理內(nèi)存,而Ashmem的共享區(qū)域在虛擬空間是連續(xù)的,物理內(nèi)存卻不一定連續(xù)。dsp和某些設(shè)備只能工作在連續(xù)的物理內(nèi)存上,這樣cpu與dsp之間的通信就需要通過Pmem來實現(xiàn)。Pmem的實現(xiàn)
Pmem的源代碼在drivers/misc/pmem.c中,Pmem驅(qū)動依賴于linux的miscdevice和platformdriver框架,一個系統(tǒng)可以有多個Pmem,默認的是最多10個。Pmem暴露4組操作,分別是platformdriver的probe和remove操作;miscdevice的fops接口和vm_ops操作。模塊初始化時會注冊一個platformdriver,在之后probe時,創(chuàng)建misc設(shè)備文件,分配內(nèi)存,完成初始化工作。Pmem通過pmem_info,pmem_data,pmem_region三個結(jié)構(gòu)體維護分配的共享內(nèi)存,其中pmem_info代表一個Pmem設(shè)備分配的內(nèi)存塊,pmem_data代表該內(nèi)存塊的一個子塊,pmem_region則把每個子塊分成多個區(qū)域。pmem_data是分配的基本單位,即每次應用層要分配一塊Pmem內(nèi)存,就會有一個pmem_data來表示這個被分配的內(nèi)存塊,實際上在open的時候,并不是open一個pmem_info表示的整個Pmem內(nèi)存塊,而是創(chuàng)建一個pmem_data以備使用。一個應用可以通過ioctl來分配pmem_data中的一個區(qū)域,并可以把它map到進程空間;并不一定每次都要分配和map整個pmem_data內(nèi)存塊。dalvik虛擬機內(nèi)存管理android模式linux模式dalvik虛擬機內(nèi)存管理內(nèi)存管理的核心就是兩個部分:分配內(nèi)存和回收內(nèi)存。Java語言使用new操作符來分配內(nèi)存,但是與C/C++等語言不同的是,Java語言并沒有提供任何操作來釋放內(nèi)存,而是通過一種叫做垃圾收集的機制來回收內(nèi)存。對于內(nèi)存管理的實現(xiàn),我們通過三個方面來加以分析:內(nèi)存分配,內(nèi)存回收和內(nèi)存管理調(diào)試。對象布局
所有的對象都有一個相同的頭部clazz和lock。
(1)clazz:clazz指向該對象的類對象,類對象用來描述該對象所屬的類,這樣可以很容易的從一個對象獲取該對象所屬的類的具體信息。
(2)lock:是一個無符號整數(shù),用以實現(xiàn)對象的同步。
(3)data:存放對象數(shù)據(jù),根據(jù)對象的不同數(shù)據(jù)區(qū)的大小是不同的。
內(nèi)存管理的主要操作之一是為Java對象分配內(nèi)存,Java對象在虛擬機中的內(nèi)存布局如下:
堆
堆是dalvik虛擬機從操作系統(tǒng)分配的一塊連續(xù)的虛擬內(nèi)存。heapBase是堆的起始地址,heapLimit是堆的最大地址,堆大小的最大值可以通過-Xmx選項或dalvik.vm.heapsize指定。在原生系統(tǒng)中,一般dalvik.vm.heapsize值是32M,在MIUI中我們將其設(shè)為64M。
在dalvik虛擬機實現(xiàn)中,是通過底層的bionicC庫的malloc/free操作來分配/釋放內(nèi)存的。bionicC庫的malloc/free操作是基于DougLea的實現(xiàn)(dlmalloc)
堆內(nèi)存位圖
在虛擬機中維護了兩個對應于堆內(nèi)存的位圖,稱為liveBits和markBits。
在對象布局中,我們看到對象最小占用8個字節(jié)。在為對象分配內(nèi)存時要求必須8字節(jié)對齊。這也就是說,對象的大小會調(diào)整為8字節(jié)的倍數(shù)。比如說一個對象的實際大小是13字節(jié),但是在分配內(nèi)存的時候分配16字節(jié)。因此所有對象的起始地址一定是8字節(jié)的倍數(shù)。堆內(nèi)存位圖就是用來描述堆內(nèi)存的,每一個bit描述8個字節(jié),因此堆內(nèi)存位圖的大小是對的64分之一。對于MIUI的實現(xiàn)來說,這兩個位圖各占1M。
liveBits的作用是用來跟蹤堆中以分配的內(nèi)存,每分配一個對象時,對象的內(nèi)存起始地址對應于位圖中的位被設(shè)為1。在下一篇垃圾收集中我們會進一步的分析liveBits和markBits這兩個位圖的作用。
dvmAllocObjectdvmAllocObject在dalvik虛擬機中,new操作符最終對應dvmAllocObject這個C函數(shù)。下面通過偽碼的形式列出dvmAllocObject的實現(xiàn)。
Object*dvmAllocObject(ClassObject*clazz,intflags){
n=getobjectsizeformclassobjectclazz
firsttry:allocatenbytesfromheap
iffirsttryfailed{
rungarbagecollectorwithoutcollectingsoftreferences
secondtry:allocatenbytesfromheap
}
ifsecondtryfailed{
thirdtry:growtheheapandallocatenbytesfromheap
(注釋:堆是虛擬內(nèi)存,一開始并未分配所有的物理內(nèi)存,只要還沒有達到虛擬內(nèi)存的最大值,可以通過獲取更多物理內(nèi)存的方式來擴展堆)
}
ifthirdtryfailed{
rungarbagecollectorwithcollectingsoftreferences
fourthtry:growthehapandallocatenbytesfromheap
}
iffourthtryfailed,returnnullpointer,dalvikvmwillabort
}
可以看出,為了分配內(nèi)存,虛擬機盡了最大的努力,做了四次嘗試。其中進行了兩次垃圾收集,第一次不收集SoftReference,第二次收集SoftReference。從中我們也可以看出垃圾收集的時機,實質(zhì)上在dalvik虛擬機實現(xiàn)中有3個時機可以觸發(fā)垃圾收集的運行:
(1)程序員顯式的調(diào)用System.gc()
(2)內(nèi)存分配失敗時
(3)如果分配的對象大小超過384KB,運行并發(fā)標記(concurrentmark),
垃圾回收在dalvik虛擬機中,內(nèi)存分配操作的流程相對比較簡單直觀,從一個堆中分配可用內(nèi)存,分配失敗時觸發(fā)垃圾收集。
垃圾收集是dalvik虛擬機內(nèi)存管理的核心,垃圾收集的性能在很大程度上影響了一個Java程序內(nèi)存使用的效率。顧名思義,垃圾收集就是收集垃圾內(nèi)存加以回收。dalvik虛擬機使用常用的Mark-Sweep算法,該算法一般分Mark階段(標記出活動對象),Sweep階段(回收垃圾內(nèi)存)和可選的Compact階段(減少堆中的碎片)。dalvik虛擬機的實現(xiàn)不進行可選的Compact階段。
Mark
垃圾收集的第一步是標記出活動對象,因為沒有辦法識別那些不可訪問的對象(unreachableobjects),因此我們只能標記出活動對象,這樣所有未被標記的對象就是可以回收的垃圾
1.1根集合(RootSet)
當進行垃圾收集時,需要停止dalvik虛擬機的運行(當然,除了垃圾收集之外)。因此垃圾收集又被稱作STW(stop-the-world,整個世界因我而停止)。dalvik虛擬機在運行過程中要維護一些狀態(tài)信息,這些信息包括:每個線程所保存的寄存器,Java類中的靜態(tài)字段,局部和全局的JNI引用,JVM中的所有函數(shù)調(diào)用會對應一個相應C的棧幀。每一個棧幀里可能包含對對象的引用,比如包含對象引用的局部變量和參數(shù)。
所有這些引用信息被加入到一個集合中,叫根集合。然后從根集合開始,遞歸的查找可以從根集合出發(fā)訪問的對象。因此,Mark過程又被成為追蹤,追蹤所有可被訪問的對象。如下圖所示,假定從根集合{a}開始,我們可以訪問的對象集合為{a,b,c,d},這樣就追蹤出所有可被訪問的對象集合。
(5.98KB)
1.2標記棧(MarkStack)
垃圾收集使用棧來保存根集合,然后對棧中的每一個元素,遞歸追蹤所有可訪問的對象,對于所有可訪問的對象,在markBits位圖中該將對象的內(nèi)存起始地址對應的位設(shè)為1。這樣當棧為空時,markBits位圖就是所有可訪問的對象集合。ConcurrentMark(并發(fā)標記)
為了運行垃圾收集,需要停止虛擬機的運行,這可能會導致程序比較長時間的停頓。垃圾收集的主要工作位于Mark階段,為了縮短停頓時間,dalvik虛擬機使用了concurrentmark技術(shù)。Concurrentmark引入一個單獨的gc線程,由該線程去跟蹤自己的根集合中所有可訪問的對象,同時所有其它的線程也在運行。這也是concurrent一詞的含義,但是為了回收內(nèi)存,即運行Sweep階段,必需停止虛擬機的運行。這會導入一個問題,即在gc線程mark對象的時候,其它線程的運行又引入了新的訪問對象。因此在Sweep階段,又重新運行mark階段,但是在這個階段對于已經(jīng)mark的對象可以不用繼續(xù)遞歸追蹤了。這樣從一定程度上降低了程序停頓時間。
Sweep垃圾收集的第二步就是回收內(nèi)存,在Mark階段通過markBit
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度法律服務機構(gòu)兼職律師服務合同3篇
- 2025年度公司簽約帶貨主播虛擬偶像合作合同3篇
- 二零二五年度養(yǎng)殖場養(yǎng)殖場養(yǎng)殖技術(shù)交流與合作合同3篇
- 2025年度建筑工程施工現(xiàn)場管理三方協(xié)議3篇
- 二零二五年度全新碼頭租賃合同及港口貨物裝卸服務協(xié)議3篇
- 2025年度XX教育機構(gòu)二零二五年度教育貸款協(xié)議3篇
- 2025年度大學畢業(yè)生就業(yè)就業(yè)能力評估與培訓合同3篇
- 2025年度高新技術(shù)產(chǎn)業(yè)競業(yè)禁止勞動合同范本解析3篇
- 2025年度高效農(nóng)業(yè)機械買賣合同協(xié)議書模板3篇
- 2025年度寵物店專業(yè)連鎖品牌形象設(shè)計與授權(quán)合同3篇
- 山東省濟南市2023-2024學年高三上學期期末學習質(zhì)量檢測生物試題(原卷版)
- 《食品包裝與安全》課件
- 內(nèi)蒙古自治區(qū)呼和浩特市部分學校2023-2024學年九年級上學期期末數(shù)學試卷
- 兒科重癥肺炎的康復治療方案
- 機械加工刀具中英文對照外文翻譯文獻
- 泰達時代中心樓頂發(fā)光字施工方案
- 七年級上冊數(shù)學期末考試(難的)
- 北京匯文中學新初一均衡分班語文試卷
- 國家開放大學電大《政治學原理》期末試題標準題庫及答案(試卷號2208)
- 作物生產(chǎn)與經(jīng)營管理專業(yè)調(diào)研報告
- 金銀花的藥理作用研究進展
評論
0/150
提交評論