我們知道,手機(jī)的內(nèi)存是有限的,如果應(yīng)用內(nèi)存占用過(guò)大,輕則引起卡頓,重則導(dǎo)致應(yīng)用崩潰或被系統(tǒng)強(qiáng)制殺掉,更嚴(yán)重的情況下會(huì)影響應(yīng)用的留存率。因此,內(nèi)存優(yōu)化是性能優(yōu)化中非常重要的一部分。但是,很多開發(fā)者對(duì)內(nèi)存的認(rèn)識(shí)還停留在應(yīng)用開發(fā)這一層,平時(shí)只是參考網(wǎng)上的方案,對(duì)內(nèi)存進(jìn)行比較淺顯的優(yōu)化。想要深入進(jìn)行內(nèi)存優(yōu)化,我們需要從操作系統(tǒng)的層面了解內(nèi)存是怎么管理的,又是如何被使用的。
成都創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供溫州網(wǎng)站建設(shè)、溫州做網(wǎng)站、溫州網(wǎng)站設(shè)計(jì)、溫州網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、溫州企業(yè)網(wǎng)站模板建站服務(wù),十多年溫州做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。可能會(huì)有人疑問:“為什么做個(gè)內(nèi)存優(yōu)化需要從操作系統(tǒng)層了解內(nèi)存呢?”我們確實(shí)可以在網(wǎng)上搜到很多內(nèi)存優(yōu)化的文章,但它們都是從上層應(yīng)用出發(fā)進(jìn)行優(yōu)化的,而不同的應(yīng)用因?yàn)榄h(huán)境不一樣、業(yè)務(wù)不一樣,很多優(yōu)化方法都不能通用。因此,只有當(dāng)我們從底層掌握了內(nèi)存的原理,從下而上地制定優(yōu)化方案,才能適用于任何業(yè)務(wù),甚至當(dāng)我們轉(zhuǎn)型到 iOS、前端或者后端都能通用。
接下來(lái),我們就從操作系統(tǒng)底層出發(fā),重新認(rèn)識(shí)內(nèi)存。
我們先將目光放到操作系統(tǒng)的早期,在這個(gè)環(huán)境下,程序都是直接操作物理內(nèi)存的。比如一個(gè)程序執(zhí)行如下指令:
MOV REGISTER1,0
計(jì)算機(jī)會(huì)將位置為 0 的物理內(nèi)存中的內(nèi)容移到 REGISTER1 的寄存器中。在這種情況下,如果第二個(gè)程序在 0 的位置寫入一個(gè)新的值,就會(huì)擦掉第一個(gè)程序存放在相同位置上的所有內(nèi)容,導(dǎo)致第一個(gè)程序崩潰。
正因?yàn)閼?yīng)用程序可以直接操作物理內(nèi)存,所以我們完全可以修改其他程序在內(nèi)存中的數(shù)據(jù),導(dǎo)致程序崩潰或者產(chǎn)生安全問題。因此,對(duì)當(dāng)時(shí)的操作系統(tǒng)來(lái)說(shuō),同時(shí)運(yùn)行多個(gè)程序很困難。
為了解決這個(gè)問題,我們自然而然會(huì)想到:不允許應(yīng)用程序直接操作物理內(nèi)存。于是虛擬內(nèi)存的技術(shù)誕生了。
為了更好地了解什么是虛擬內(nèi)存,我們先看看早期直接操作物理內(nèi)存系統(tǒng)下的內(nèi)存模型長(zhǎng)什么樣。從下面內(nèi)存模型的簡(jiǎn)化圖中我們可以看到,物理內(nèi)存中存在兩塊數(shù)據(jù),一個(gè)是操作系統(tǒng)的數(shù)據(jù),一個(gè)是應(yīng)用程序的數(shù)據(jù)。除此之外,其實(shí)還會(huì)有設(shè)備驅(qū)動(dòng)程序的數(shù)據(jù),它們不是我們了解的重點(diǎn)就先不列上去了。
什么是虛擬內(nèi)存?虛擬內(nèi)存技術(shù)相當(dāng)于給每個(gè)程序一個(gè)獨(dú)占且連續(xù)的內(nèi)存,比如 32 位系統(tǒng)下是 4G(2^32),只不過(guò)這個(gè)內(nèi)存是虛擬的。同時(shí),虛擬內(nèi)存需要能夠映射到真實(shí)的物理內(nèi)存。簡(jiǎn)化的內(nèi)存模型如下
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-haHe4vHL-1670148923898)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/edd00859a2094eaa964f8ce588df1f18~tplv-k3u1fbpfcp-watermark.image?)]
從上圖的簡(jiǎn)化內(nèi)存模型,我們可以看到,每個(gè)程序都可以獨(dú)享一塊虛擬內(nèi)存。在 Linux 系統(tǒng)上,一個(gè)進(jìn)程代表著一個(gè)程序,這里我們可以理解成每個(gè)進(jìn)程都獨(dú)享一塊虛擬內(nèi)存,這塊虛擬內(nèi)存在 32 位系統(tǒng)下是 4G(2^32),64 位系統(tǒng)下是 2^48,即 256TB(這里不是 2^64,是因?yàn)?256TB 已經(jīng)足夠大了,如果用 2^64,會(huì)有大量的尋址空間浪費(fèi))。
其次,虛擬內(nèi)存都由應(yīng)用程序和操作系統(tǒng)這兩部分組成。其中,應(yīng)用程序這部分虛擬內(nèi)存是應(yīng)用獨(dú)占的,操作系統(tǒng)這部分虛擬內(nèi)存則由所有進(jìn)程共享,而所有進(jìn)程的操作系統(tǒng)這部分虛擬內(nèi)存都指向了同一段物理內(nèi)存。虛擬內(nèi)存到物理內(nèi)存的映射由操作系統(tǒng)來(lái)實(shí)現(xiàn),操作系統(tǒng)在做映射操作時(shí)會(huì)尋找可用的物理內(nèi)存,不可能出現(xiàn)覆蓋其他數(shù)據(jù)的情況,這讓同時(shí)運(yùn)行多個(gè)程序成為了可能。
上圖的虛擬內(nèi)存是一個(gè)簡(jiǎn)化的模型。實(shí)際上,虛擬內(nèi)存和物理內(nèi)存都是按照頁(yè)來(lái)管理和映射的,一頁(yè)的大小為 4KB,我們來(lái)看一個(gè) 32 位 Android 系統(tǒng)、物理內(nèi)存為 2G 的設(shè)備的內(nèi)存模型。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-ysAU5ah2-1670148923899)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/efb87e2370624ccdb09642d2018c0581~tplv-k3u1fbpfcp-watermark.image?)]
可以看到,物理內(nèi)存和虛擬內(nèi)存是通過(guò) 4K 大小的頁(yè)一一對(duì)應(yīng)的。這個(gè)時(shí)候,如果我們?cè)儆梦恼伦铋_頭的那個(gè)指令:
MOV REGISTER1,0
在虛擬內(nèi)存技術(shù)的加持下,此時(shí)計(jì)算機(jī)就不會(huì)直接將物理地址為 0 的內(nèi)存移到 REGISTER1 寄存器了,而是先尋找虛擬地址 0 對(duì)應(yīng)的物理地址 4096,然后將物理地址為 4096 的內(nèi)容移到 REGISTER1 寄存器中
MOV REGISTER1,4096
虛擬地址轉(zhuǎn)換成物理地址是由計(jì)算機(jī)的內(nèi)存管理單元(MMU)完成的,它屬于硬件部分而不是系統(tǒng)軟件部分,所以轉(zhuǎn)換速度很快。
虛擬內(nèi)存的內(nèi)存模型知道了虛擬內(nèi)存由操作系統(tǒng)和應(yīng)用程序兩部分組成,并且虛擬內(nèi)存都由頁(yè)來(lái)維護(hù)和管理之后,我們?cè)偕钊肓私庖幌?Linux 系統(tǒng)中虛擬內(nèi)存的內(nèi)存模型,它需要和 Linux 系統(tǒng)的可執(zhí)行文件,也就是 ELF 文件一起配合來(lái)看。
為了讓你理解起來(lái)更簡(jiǎn)單,這里的 ELF 文件格式也被我簡(jiǎn)化了,后面用到的時(shí)候再進(jìn)行深入介紹。在 Linux 系統(tǒng)中,存放操作系統(tǒng)的虛擬內(nèi)存區(qū)域被稱為內(nèi)核空間,剩下的存放應(yīng)用的虛擬內(nèi)存區(qū)域稱為用戶空間。 內(nèi)核空間占用了 1G,位于虛擬地址的高地址區(qū)域,而 ELF 文件的一些數(shù)據(jù),是存放在低地址的區(qū)域(即從地址 0 開始)。下面我詳細(xì)解釋一下內(nèi)存模型中的幾個(gè)區(qū)域
棧:由編譯器自動(dòng)分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。
堆:動(dòng)態(tài)內(nèi)存分配,可以由開發(fā)者自己分配和釋放(malloc 和 free 函數(shù)實(shí)現(xiàn)),Android 開發(fā)時(shí)不需要我們手動(dòng)分配和釋放,因?yàn)樘摂M機(jī)程序已經(jīng)幫我們做了。堆的開始地址由變量 start_brk 描述,堆的當(dāng)前地址由變量 brk 描述。
BSS:存放全局未初始化,靜態(tài)未初始化數(shù)據(jù)。
數(shù)據(jù)段:存放全局初始化,靜態(tài)初始化數(shù)據(jù)。
程序代碼區(qū):存放的是 ELF 文件代碼段。
可以看到,棧內(nèi)存的分配是從上到下的,而堆內(nèi)存的分配是從下到上的,這種方式可以大程度利用虛擬內(nèi)存的空間。
虛擬內(nèi)存分配前面我們已經(jīng)知道,應(yīng)用是沒法直接操作物理內(nèi)存的,所以我們?cè)陂_發(fā) App 時(shí)分配的內(nèi)存實(shí)際都是虛擬內(nèi)存。那么我們?cè)趺瓷暾?qǐng)?zhí)摂M內(nèi)存呢?
開發(fā) Android 應(yīng)用時(shí),并不需要我們自己去分配內(nèi)存,直接 new 一個(gè)對(duì)象,聲明一個(gè)變量或者常量即可,也不需要我們自己去做釋放,但所有的數(shù)據(jù)都需要內(nèi)存,這些都是虛擬機(jī)幫我們做。虛擬機(jī)分配申請(qǐng)內(nèi)存主要使用的是 malloc() 函數(shù),它是 C 語(yǔ)言庫(kù)的一個(gè)標(biāo)準(zhǔn)函數(shù)。
void *malloc(size_t size)
malloc 函數(shù)是一個(gè) C 語(yǔ)言庫(kù)的函數(shù),所以它分配內(nèi)存最終還是得調(diào)用 Linux 系統(tǒng)提供的函數(shù),讓 Linux 內(nèi)核去幫我們申請(qǐng)一塊內(nèi)存。內(nèi)核會(huì)調(diào)用 mmap() 函數(shù),在堆中分配我們想要的內(nèi)存空間大小。 mmap() 函數(shù)是 Linux 系統(tǒng)一個(gè)很重要的函數(shù),我們需要深刻認(rèn)識(shí)它。
void *mmap(void *addr,size_t length,int prot,int flags,int fd, off_t offset);
mmap 函數(shù)有 2 種用法:
第 1 種用法可以讓我們讀文件的效率更高(比如 Android 讀取 dex 文件就是通過(guò) mmap 來(lái)提高讀取速度),也可以用來(lái)實(shí)現(xiàn)數(shù)據(jù)跨進(jìn)程傳輸(比如 Android 共享內(nèi)存機(jī)制、Binder 通信都是通過(guò) mmap 來(lái)實(shí)現(xiàn)的)。malloc() 函數(shù)使用了 mmap 函數(shù)的第 2 種用法,即在 Heap 區(qū)域中申請(qǐng)一塊內(nèi)存。
需要注意的,這里申請(qǐng)的內(nèi)存都是虛擬內(nèi)存,并且這個(gè)時(shí)候并不會(huì)分配真正的物理內(nèi)存,只有當(dāng)我們真正要往這塊虛擬內(nèi)存區(qū)域?qū)懭霐?shù)據(jù)時(shí),操作系統(tǒng)檢查到對(duì)應(yīng)的虛擬內(nèi)存沒有映射到物理內(nèi)存,便會(huì)發(fā)生缺頁(yè)中斷,然后分配一塊同樣大小的物理內(nèi)存,并建立映射關(guān)系。這是一種懶加載技術(shù),也是內(nèi)存優(yōu)化的方案之一。
malloc() 函數(shù)在申請(qǐng)內(nèi)存小于 128k 時(shí)會(huì)使用 sbrk() 函數(shù),sbrk() 會(huì)將堆頂指針(即前面提到的 brk)向高地址移動(dòng),獲得新的虛存空間,這些策略都是基于性能考慮的。比如 Android 虛擬機(jī)在分配大對(duì)象時(shí),也會(huì)專門放在 LargeObjectSpcace 中,這些就不展開講了。至于 Linux 系統(tǒng)是如何發(fā)生缺頁(yè)中斷,如何分配物理內(nèi)存,如何建立映射關(guān)系的,都屬于 Linux 系統(tǒng)相關(guān)知識(shí)了,更詳細(xì)的知識(shí)點(diǎn)會(huì)在后面的篇章中結(jié)合實(shí)戰(zhàn)項(xiàng)目穿插著講解。
小結(jié)事實(shí)上,直接操作物理內(nèi)存的操作系統(tǒng)并沒有消失,我們現(xiàn)在的嵌入式設(shè)備,如冰箱,微波爐等等都能直接操作物理內(nèi)存。這其實(shí)也符合它們的使用場(chǎng)景,直接操作物理內(nèi)存會(huì)讓性能開銷更小,操作也更方便。但需要同時(shí)運(yùn)行多個(gè)軟件的系統(tǒng)都有虛擬內(nèi)存,可以說(shuō)虛擬內(nèi)存是現(xiàn)代操作系統(tǒng)最重要的發(fā)明之一了。
當(dāng)我們重新認(rèn)識(shí)了內(nèi)存后,我們?cè)賮?lái)看內(nèi)存優(yōu)化,它其實(shí)分為兩部分。
在后面的章節(jié)中,我會(huì)針對(duì)這兩部分,總結(jié)出體系的優(yōu)化方法論,再搭配講解一些優(yōu)化實(shí)踐。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
當(dāng)前名稱:內(nèi)存優(yōu)化之重新認(rèn)識(shí)內(nèi)存-創(chuàng)新互聯(lián)
本文鏈接:http://jinyejixie.com/article14/dedgge.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、虛擬主機(jī)、響應(yīng)式網(wǎng)站、小程序開發(fā)、動(dòng)態(tài)網(wǎng)站、微信公眾號(hào)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容