欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

Linux應用開發(fā)之共享內(nèi)存

嵌入式應用研究院 ? 來源:TLPI系統(tǒng)編程筆記 ? 2023-04-06 09:51 ? 次閱讀

概述

mmap() 系統(tǒng)調(diào)用在調(diào)用進程的虛擬地址空間中創(chuàng)建一個新的內(nèi)存映射,映射分為兩種:

文件映射:將一個文件的一部分直接映射到調(diào)用進程的虛擬內(nèi)存中,一旦一個文件被映射之后,就可以通過在相應的內(nèi)存區(qū)域中操作字節(jié)來訪問文件內(nèi)容,映射的分頁會在需要的時候從文件中自動加載,這種映射也稱為基于文件的映射或內(nèi)存映射文件

匿名映射:沒有對應的文件,相反,這種映射的分頁會被初始化為 0

一個進程的映射中的內(nèi)存可以與其他進程中的映射共享(即各個子進程的頁表條目指向 RAM 中相同的分頁)。這種情況會存在2種情況發(fā)生:

當兩個進程映射了一個文件的同一個區(qū)域時,它們會共享物理內(nèi)存的相同分頁

通過 fork() 創(chuàng)建的子進程會繼承父進程的映射的副本,并且這些映射所引用的物理內(nèi)存分頁與父進程中相應映射所引用的分頁相同

當兩個或者多個進程共享相同分頁時,每個進程都有可能看到其他進程對分頁內(nèi)容作出的改變,這當然要取決于映射是私有的還是共享的:

私有映射(MAP_PRIVATE) :在映射內(nèi)容上發(fā)生的變更對其他進程是不可見的,對于文件映射來說,變更將不會在底層文件上進行。盡管一個私有映射的分頁在上面介紹的情況中, 初始時是共享的,但對映射內(nèi)容作出的變更對各個進程來講是私有的。內(nèi)核使用了寫時復制技術(shù)完成了這個任務。這意味著,當一個進程試圖修改一個分頁 的內(nèi)容時,內(nèi)核首先會為該進程創(chuàng)建一個新分頁,并將需要修改的分頁中的內(nèi)容復制到新分頁中(以及調(diào)整進程的頁表)。正因為這個原因,MAP_PRIVATE 映射會被稱為私有,寫時復制映射

共享映射(MAP_SHARED):在映射內(nèi)容上發(fā)生的變更對所有共享同一個映射的其他進程都是可見的,對于文件映射來說,變更將會發(fā)生在底層文件上

各種映射的用途:13e96f22-d40d-11ed-bfe3-dac502259ad0.png

私有文件映射:映射的內(nèi)容被初始化為一個而文件區(qū)域的內(nèi)容。多個映射同一個文件的進程初始時會共享同樣的內(nèi)存物理分頁,但系統(tǒng)使用寫時復制技術(shù)使得一個進程對映射所做的變更對其他進程不可見。這種映射的主要用途是使用一個文件的內(nèi)容來來初始化一塊內(nèi)存區(qū)域。一些常見的例子包括根據(jù)二進制可執(zhí)行文件或共享文件的相應部分來初始化一個進程的文件和數(shù)據(jù)段

私有匿名映射:每次調(diào)用 mmap() 創(chuàng)建一個私有映射時都會產(chǎn)生一個新映射,該映射與同一進程創(chuàng)建的其他匿名映射是不同的(即不會共享物理分頁)。盡管子進程會繼承父進程的映射,但寫時復制語義確保了 fork() 之后父進程和子進程不會看到其他進程對映射所做的變更。匿名映射的主要用途是為一個進程分配新(用0填充)的內(nèi)存(如在分配大塊內(nèi)存時用 malloc() 會為此使用 mmap())

共享文件映射:所有映射一個文件同一區(qū)域的進程會共享同樣的內(nèi)存物理分頁,這些分頁的內(nèi)容將被初始化為該文件區(qū)域。對映射內(nèi)容的修改將直接在文件中進行。這種映射主要用于2個用途:

允許內(nèi)存映射 IO, 這表示一個文件會被加載到進程的虛擬內(nèi)存中的一個區(qū)域中并且對該區(qū)域的變更會自動被寫入到這個文件中。因此,內(nèi)存映射 IO 為使用 read(),write() 來執(zhí)行文件 IO 這種做法提供了一種替代方案。

允許無關進程共享一塊內(nèi)容以便以一種類似于 System V 共享內(nèi)存段的方式來執(zhí)行(快速) IPC

共享匿名映射:與私有匿名映射一樣,每次調(diào)用 mmap() 創(chuàng)建一個共享匿名映射時都會產(chǎn)生一個新的,與任何其他映射不共享分頁的截然不同的映射。這里的區(qū)別是映射的分頁不會被寫時復制。這意味著, 當一個子進程在 fork() 之后繼承映射,父進程和子進程共享同一的 RAM 分頁,并且一個進程對映射內(nèi)容所作出的變更會對其他進程可見。共享匿名映射允許以一種類似于 System V 共享內(nèi)存段的方式來進行 IPC,但只有相關進程可以這么做

一個進程在執(zhí)行 exec() 后映射會丟失,但通過 fork() 創(chuàng)建的子進程會繼承映射,映射類型(MAP_PRIVATE 和 MAP_SHARED) 也會被繼承。通過 Linux 下特有的 /proc/PID/maps 文件能夠查看與一個進程的映射有關的所有信息。

創(chuàng)建一個映射

#include

void*mmap(void*addr,size_tlength,intprot,intflags,intfd,off_toffset);

addr建立映射區(qū)的首地址,由 Linux 內(nèi)核指定。用戶程序調(diào)用時直接傳遞NULL,那么內(nèi)核會為映射選擇一個合適地址,如果不是NULL,內(nèi)核會再選擇將映射放置在何處時將這個參數(shù)值作為一個提示信息來處理

成功時返回創(chuàng)建的映射區(qū)首地址,失敗時返回MAP_FAILED

length指定了映射的字節(jié)數(shù),盡管length無需是一個系統(tǒng)分頁大小的倍數(shù),但是內(nèi)核會以分頁大小為單位來創(chuàng)建映射,因此,實際上lenght會被向上提升為分頁大小的下一個倍數(shù)

prot映射區(qū)的權(quán)限:

1408b9ae-d40d-11ed-bfe3-dac502259ad0.png

flags` 標志位參數(shù),常用于設定更新物理區(qū)域、設置共享、創(chuàng)建匿名映射區(qū):

MAP_SHARED:創(chuàng)建一個共享映射,映射區(qū)所做的修改會反映到物理設備(磁盤)上

MAP_PRIVATE:創(chuàng)建一個私有映射,映射區(qū)所做的修改不會反映到物理設備上

fd是用來建立映射區(qū)的文件描述符。

offset映射文件的偏移量,它必須是系統(tǒng)分頁大小的整數(shù)倍,可以映射整個文件,也可以只映射一部分內(nèi)容

有關內(nèi)存保護的更多細節(jié)

如果一個進程在訪問一個內(nèi)存區(qū)域時違反了該區(qū)域上的保護位,那么內(nèi)核會向該進程發(fā)送一個SIG_SEGV信號。

標記為PROT_NONE的分頁內(nèi)存的一個用途是作為一個進程分配的內(nèi)存區(qū)域的起始位置或結(jié)束位置的守護分頁,如果進程意外地訪問了標記為PROT_NONE的分頁,那么內(nèi)核會通過一個SIGSEGV信號來通知該進程。

內(nèi)存保護信息駐留在進程的私有虛擬內(nèi)存表中,因此不同的進程可能會使用不同的保護位來映射同一個內(nèi)存區(qū)域。

標準中規(guī)定的對offset和addr的對齊約束

SUSv3 規(guī)定mmap()的offset參數(shù)必須要與分頁對齊,而addr參數(shù)在指定了MAP_FIXED的情況下也必須要與分頁對齊。

SUSV4 放寬了這些要求:

一個實現(xiàn)可能會要求offset為系統(tǒng)分頁大小的倍數(shù)

如果指定了MAP_FIXED,那么一個實現(xiàn)可能會要求addr是分頁對齊的

如果指定了MAP_FIXED,并且addr為非零值,那么addr和offset除以系統(tǒng)分頁大小所得的余數(shù)應該相等

解除映射區(qū)域

#include

intmunmap(void*addr,size_tlength);

munmap()與mmap()` 操作相反,即從調(diào)用進程的虛擬地址空間中刪除一個映射

addr參數(shù)是待解除映射的地址范圍的起始地址,它必須與一個分頁邊界對齊

length參數(shù)是一個非負整數(shù),它指定了待解除映射區(qū)域的大小,范圍為系統(tǒng)分頁大小的下一個倍數(shù)的地址空間將會解除映射

通常會解除整個映射,因此將addr指定為上一個mmap()調(diào)用返回的地址,并且length的值與mmap()調(diào)用中使用的length的值一樣。也可以解除一個映射中的部分映射,這樣原來的映射要么會收縮,要么會被分為兩個,這取決于在何處開始解除映射。還可以指定一個跨越多個映射的地址范圍,這樣的話所有范圍內(nèi)的映射都會被解除

如果在addr和length指定的地址范圍中不存在映射,那么munmap()將不起任何作用并返回 0

在解除映射期間,內(nèi)核會刪除進程持有的在指定地址范圍內(nèi)的所有內(nèi)存鎖

當一個進程終止或執(zhí)行了一個exec()之后進程中所有的映射會自動解除

為確保一個共享文件映射的內(nèi)容會被寫入到底層文件中,在使用munmap()解除一個映射之前需要調(diào)用msync()

文件映射

創(chuàng)建一個文件映射的步驟:

獲取一個文件的描述符,通常通過調(diào)用open()來獲取

將文件描述符作為fd參數(shù),傳入mmap()調(diào)用中

執(zhí)行上面操作之后,mmap()會將打開的文件的內(nèi)容映射到調(diào)用進程的地址空間。一旦mmap()被調(diào)用之后就能夠關閉文件描述符了,而不會對映射產(chǎn)生任何影響。

除了普通的磁盤文件,使用mmap()還能夠映射各種真實和虛擬設備的內(nèi)容,如硬盤,光盤以及/dev/mem。

在打開描述符fd引用的文件時必須要具備與port和flags參數(shù)值匹配的權(quán)限。

offset參數(shù)指定了從文件區(qū)域中的哪個字節(jié)開始映射,它必須是系統(tǒng)分頁大小的倍數(shù),將offset指定為 0 會導致從文件的起始位置開始映射,length參數(shù)指定了映射的字節(jié)數(shù)。

141eaad4-d40d-11ed-bfe3-dac502259ad0.png

私有文件映射

私有文件映射用途:

允許多個執(zhí)行同一程序或者使用同一個共享庫的進程共享同樣(只讀的)文本段,它是從底層可執(zhí)行文件或庫文件的相應部分映射而來的

映射一個可執(zhí)行文件或共享庫的初始化數(shù)據(jù)段。這種映射會被處理成私有,使得對映射數(shù)據(jù)段內(nèi)容的變更不會發(fā)生在底層文件上

mmap()的這兩種用法通常對程序是不可見的,因為這些映射是由程序加載器和動態(tài)鏈接器創(chuàng)建的,可以在/proc/PID/maps中發(fā)現(xiàn)這兩種映射。

共享文件映射

當多個進程創(chuàng)建了同一個文件區(qū)域的共享映射時,它們會共享同樣的內(nèi)存物理分頁。此外,對映射內(nèi)容的變更將會反應到文件上。共享文件映射有兩個用途:內(nèi)存映射 IO 和 IPC。

1436603e-d40d-11ed-bfe3-dac502259ad0.png

內(nèi)存映射 IO

由于共享文件映射中的內(nèi)容是從文件初始化而來,并且對映射內(nèi)容所做的變更都會自動反應到文件上,因此可以簡單的通過訪問內(nèi)存中的字節(jié)來執(zhí)行文件 IO,而 依靠內(nèi)核來確保對內(nèi)存的變更會被傳遞到映射文件上。(一般來說,一個程序會定義一個結(jié)構(gòu)化數(shù)據(jù)類型來與磁盤文件中的內(nèi)容對應起來,然后使用該數(shù)據(jù)類型來轉(zhuǎn)換映射的內(nèi)容)這項技術(shù)被稱為內(nèi)存映射 IO,它是使用read()和write()來訪問文件內(nèi)容這種方法的替代方案。

內(nèi)存映射 IO 具備兩個潛在的優(yōu)勢:

使用內(nèi)存訪問來代替read()和write()系統(tǒng)調(diào)用能夠簡化一些應用程序的邏輯

在一些情況下,它能夠比使用傳統(tǒng)的 IO 系統(tǒng)調(diào)用執(zhí)行文件 IO 這種做法提供更好的性能

內(nèi)存映射 IO 之所以能夠帶來性能的優(yōu)勢的原因如下:

正常的read()或者write()需要兩次傳輸,一次是在文件和內(nèi)核高速緩沖區(qū)之間,另一次是在高速緩沖區(qū)和用戶空間緩沖區(qū)之間,使用mmap()就無需第二次傳輸:

對于輸入:一旦內(nèi)核將相應的文件塊映射進內(nèi)存之后用戶進程就能夠使用這些數(shù)據(jù)

對于輸出:用戶進程僅僅需要修改內(nèi)存中的內(nèi)容,然后可以依靠內(nèi)核內(nèi)存管理器來自動更新底層的文件

mmap()還能夠通過減少所需使用的內(nèi)存來提升性能,當使用read()或write()時,數(shù)據(jù)將被保存在兩個緩沖區(qū)中:一個位于用戶空間,另一個位于內(nèi)核空間,當使用mmap()時,內(nèi)核空間和用戶空間會共享同一個緩沖區(qū),此外,如果多個進程正在在同一個文件上執(zhí)行 IO,那么它們通過使用mmap()就能夠共享同一個內(nèi)核緩沖區(qū),從而又能夠節(jié)省內(nèi)存的消耗

內(nèi)存映射 IO 所帶來的性能優(yōu)勢在大型文件執(zhí)行重復隨機訪問時最有可能提現(xiàn)出來。對于小數(shù)據(jù)量 IO 來講,內(nèi)存映射 IO 的開銷實際上要比簡單的read()或write()大。

使用共享文件映射的 IPC

由于所有使用同樣文件區(qū)域的共享映射的進程共享同樣的內(nèi)存物理分頁,因此共享文件映射的第二個用途就是作為一種 IPC 方法。這種共享內(nèi)存區(qū)域與 System V 共享內(nèi)存對象之間的區(qū)別在于,區(qū)域上的內(nèi)容的更變會反應到底層的映射文件上。這種特性對于那些需要共享內(nèi)容在應用程序或系統(tǒng)重啟時能夠持久化的應用程序來說是非常有用的。

邊界情況

在很多情況下,一個映射的大小是系統(tǒng)分頁大小的整數(shù)倍,并且映射會完全落入映射文件的范圍之內(nèi),但這個要求不是必須的。

映射完全落入映射文件的范圍之內(nèi)但區(qū)域大小并不是系統(tǒng)分頁大小的一個整數(shù)倍的情況,假設分頁大小為 4096 字節(jié):

144f62be-d40d-11ed-bfe3-dac502259ad0.png

由于映射大小不是系統(tǒng)分頁大小的整數(shù)倍,因此它會被向上舍入到系統(tǒng)分頁大小的下一個整數(shù)倍。當映射擴充過了底層文件的結(jié)尾處時,情況更加復雜:

147722cc-d40d-11ed-bfe3-dac502259ad0.png

雖然向上舍入的字節(jié)是可以訪問的,但它們不會被映射到底層文件上,這部分會被初始化為0。

通過擴展文件的大小(如使用ftruncate()或write()) 可以使得這種映射中之前不可訪問的部分變得可用。

內(nèi)存保護和文件訪問模式交互

一般從原則來講:

PROT_READ和PROT_EXEC保護要求被映射的文件使用O_RDONLY或O_RDWR打開

PROT_WRITE保護要求被映射的文件使用O_WRONLY或O_RDWR打開

但是,由于一些硬件架構(gòu)提供的內(nèi)存保護粒度有限,因此情況會變得復雜:

所有內(nèi)存保護組合與使用O_RDWR標記打開文件是兼容的

沒有內(nèi)存保護組合

使用O_RDONLY標記打開一個文件的結(jié)果依賴于在調(diào)用mmap()時是否指定了可以指定任意的內(nèi)存保護組合,因為對于一個MAP_PRIVATE分頁內(nèi)容做出的變更不會被寫入到文件中

同步映射區(qū)域

內(nèi)核會自動將發(fā)生在MAP_SHARED映射內(nèi)容上的變更寫入到底層文件中的,但默認情況下,內(nèi)核不保證這種同步操作會在何時發(fā)生。

#include

intmsync(void*addr,size_tlength,intflags);

msync()系統(tǒng)調(diào)用讓應用程序能夠顯式地控制何時完成共享映射與映射文件之間的同步

addr和length指定了需同步的內(nèi)存區(qū)域的起始地址和大小

flags參數(shù)的可取值:

MS_SYNC:執(zhí)行一個同步的文件寫入。這個調(diào)用會阻塞直到內(nèi)存區(qū)域中所有被修改過的分頁被寫入底層磁盤為止

MS_ASYNC:執(zhí)行一個異步寫入。內(nèi)存區(qū)域中被修改的分頁會在后面某個時刻被寫入磁盤并立即在相應文件區(qū)域中執(zhí)行read()的其他進程可見

另外一種區(qū)分這兩個值的方式可以表述為,在MS_SYNC操作之后,內(nèi)存區(qū)域會與磁盤同步,而在MS_ASYNC之后,內(nèi)存區(qū)域僅僅是與內(nèi)核高速緩沖區(qū)同步。

flags參數(shù)還可以加上下面這個值:

MS_INVALIDATE:使映射數(shù)據(jù)的緩存副本失效,當內(nèi)存區(qū)域中所有被修改過的分頁被同步到文件中之后,內(nèi)存區(qū)域中所有與底層文件不一致的分頁會被標記為無效,當下次引用這些分頁時會從文件的相應位置處復制相應的分頁內(nèi)容,其結(jié)果是其他進程對文件做出的所有更新將會在內(nèi)存區(qū)域中可見

其他mmap()標記

mmap()的flags參數(shù)的位掩碼值:

1498cd00-d40d-11ed-bfe3-dac502259ad0.png

MAP_ANONYMOUS:創(chuàng)建一個匿名映射,即沒有底層文件對應的映射

MAP_HUGETLB:與SHM_HUGETLB標記在 System V 共享內(nèi)存段中所起的作用一樣

MAP_LOCKED:按照mlock()的方式預加載映射分頁并將映射分頁鎖進內(nèi)存

MAP_NORESERVE:這個標記用來控制是否提前為映射的交換空間執(zhí)行預留操作

MAP_POPULATE:填充一個映射的分頁,對于文件映射來將,這將會在文件上執(zhí)行一個超前讀取

MAP_UNINITIALIZED:指定一個標記會防止一個匿名映射被清零,它能夠帶來性能上的提升,但同時也帶來了安全風險,因為已分配的分頁中可能會包含上一個進程留下來的敏感信息

匿名映射

匿名映射是沒有對應文件的一種映射。

MAP_ANONYMOUS和/dev/zero

在Linux 中,使用mmap()創(chuàng)建匿名映射存在2種不同但等級的方法:

在flags中指定MS_ANONYMOUS并將fd指定為 -1

打開/dev/zero設備文件,并將得到的文件描述符傳遞給mmap()

不管使用哪種方法,得到映射中的字節(jié)會被初始化為 0。offset參數(shù)都將會被忽略,因為沒有底層文件,所以也無法指定偏移量。

MAP_PRIVATE匿名映射

MAP_PRIVATE匿名映射用來分配進程私有的內(nèi)存塊并將其中的內(nèi)容初始化為 0。

下面的代碼使用/dev/zero技術(shù)創(chuàng)建一個MAP_PRIVATE匿名映射:

fd=open("/dev/zero",O_RDWR);
if(fd==-1)
errExit("open");
addr=mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
if(addr==MAP_FAILED)
errExit("mmap");

MAP_SHARED匿名映射

MAP_SHARED匿名映射允許相關進程共享一塊內(nèi)存區(qū)域而無需一個對應的映射文件。

使用MAP_ANONYMOUS技術(shù)創(chuàng)建一個MAP_SHARED匿名映射:

addr=mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,-1,0);
if(addr==MAP_FAILED)
errExit("mmap");

重新映射一個映射區(qū)域

UNIX 實現(xiàn)上一旦映射被創(chuàng)建,其位置和大小就無法改變了。Linux 提供mremap()系統(tǒng)調(diào)用可以執(zhí)行此類變更。

#define_GNU_SOURCE
#include

void*mremap(void*old_address,size_told_size,size_tnew_size,intflags,.../*void*new_address*/);

old_address和old_size指定了需要擴展或收縮的既有映射的位置和大小

在執(zhí)行重映射的過程中內(nèi)核可能會為映射進程的虛擬地址空間中重新指定一個位置,是否允許這種行為由flag參數(shù)來控制:

MREMAP_MAYMOVE:內(nèi)核可能會為映射在進程的虛擬地址空間中重新指定一個位置,如果沒有指定這個標記,并且在當前位置處沒有足夠的空間來擴展這個映射,那么就返回ENOMEM錯誤

MREMAP_FIXED:只能和MREMAP_MAYMOVE一起使用,如果指定了這個標記,那么mremap()會接收一個額外的參數(shù)void *new_address,該參數(shù)指定了一個分頁對齊的地址,并且映射將會被遷移至該地址處

mremap()成功時返回映射的起始地址

MAP_NORESERVE和過度利用交換空間

一些應用程序會創(chuàng)建大的映射,但之用映射區(qū)域中的一小部分。如果內(nèi)核總是為此類映射分配(或者預留)足夠的交換空間,那么很多交換空間可能會被浪費。相反,內(nèi)核可以只在需要的時候用到映射分頁的時候(即當應用程序訪問分頁時)為它們預留交換空間,這種方法稱為懶交換預留。它的一個優(yōu)點是,應用程序總共使用的虛擬內(nèi)存量能夠超過 RAM 加上交換空間的總量。

懶交換預留允許交換空間被過度利用,這種方式能夠很好地工作,只要所有進程都不試圖訪問整個映射,但如果所有應用程序都試圖訪問整個映射,那么 RAM 和交換空間就會被耗盡。在這種情況下,內(nèi)核會通過殺死系統(tǒng)中的一個或多個進程來降低內(nèi)存壓力。

內(nèi)核如何處理交換空間的預留是由調(diào)用mmap()時是否使用了MAP_NORESERVE標記以及影響系統(tǒng)層面的交換空間過度利用操作的/proc接口來控制的:

14bbac12-d40d-11ed-bfe3-dac502259ad0.png

Linux 特有的/proc/sys/vm/overcommit_memory文件包含了一個整數(shù)值,它控制著內(nèi)核對交換空間過度利用的處理。

過度利用監(jiān)控只適用于下面的這些映射:

私有可寫映射,這種映射的交換開銷等于所有使用該映射的進程為該映射所分配的空間總和

共享匿名映射,這種映射的交換開銷等于映射的大小

為只讀私有映射預留交換空間是沒有必要的,因為映射中的內(nèi)容是不可變更的,從而無需使用交換空間,共享文件映射也不需要使用交換空間,因為映射文件本身擔當了映射的交換空間。

當一個子進程在fork()調(diào)用中繼承了一個映射時,它將會繼承該映射的MAP_NORESERVER設置。

OOM 殺手

內(nèi)核中用來在內(nèi)存被耗盡時選擇殺死哪個進程的代碼通常被稱為out-of-memory(OOM) 殺手,OOM 殺手會嘗試選擇殺死能夠緩解內(nèi)存消耗情況的最佳進程,這里的 “最佳” 是由一組因素決定的。如一個進程消耗的內(nèi)存越多,它越可能成為 OOM 殺手選擇的目標。內(nèi)核一般不會殺死下列進程:

特權(quán)進程,因為它們可能正在執(zhí)行重要的任務

正在訪問裸設備的進程,因為殺死它們可能會導致設備處理一個不可用的狀態(tài)

已經(jīng)運行了很長時間或已經(jīng)消耗了大量 CPU 的進程,因為殺死它們可能會導致丟失很多 "工作"

為殺死一個被選中的進程,OOM 殺手會向其發(fā)送一個SIGKILL信號。

Linux 特有的/proc/PID/oom_score文件給出了在需要調(diào)用 OOM 殺手時內(nèi)核賦予給每個進程的權(quán)重。在這個文件中,進程的權(quán)重越大,那么在必要的時候被 OOM 殺手選中的可能性就越大。

Linux 特有的/proc/PID/oom_adj文件能夠用來影響一個進程的oom_score值,這個文件可以被設置成[-16,15]之間的任意一個值,其中負數(shù)會減小oom_score的值,而整數(shù)則會增大oom_score的值,-17會完全將進程從 OOM 殺手的候選目標中刪除。

MAP_FIXED標記

在mmap()中的flags參數(shù)指定MAP_FIXED標記會強制內(nèi)核原樣地解釋addr中的地址,而不是只將其作為一種提示信息。如果指定了MAP_FIXED,那么addr就必須是分頁對齊的。

一般在一個可移植的應用程序不應該使用MAP_FIXED,并且需要將addr指定為NULL。

如果在調(diào)用mmap()時指定了MAX_FIXED,并且內(nèi)存區(qū)域的起始位置為addr,覆蓋的 length 字節(jié)與之前的映射分頁重疊了,那么重疊的分頁會被新映射替換,使用這個特性可以可移植地將一個文件或者多個文件的多個部分映射進一塊連續(xù)的內(nèi)存區(qū)域:

使用mmap()創(chuàng)建一個匿名映射,addr指定為NULL,并且不指定MAP_FIXED,這樣就允許內(nèi)核為映射選擇一個地址

使用一系列指定了MAP_FIXED標記的mmap()調(diào)用來將文件區(qū)域映射進在上一步中創(chuàng)建的映射的不同部分

從 Linux 2.6 開始,使用remap_file_pages()系統(tǒng)調(diào)用也能夠取得同樣的效果,但是使用MAP_FIXED的可移植性更強,因為remap_file_pages()是 Linux 特有的。

非線性映射

使用mmap()創(chuàng)建的文件映射是連續(xù)的:映射文件的分頁與內(nèi)存區(qū)域的分頁存在一個順序的,一對一的對應關系。

但是一些應用程序需要創(chuàng)建大量的非線性映射:

14de24b8-d40d-11ed-bfe3-dac502259ad0.png

使用多個帶MAP_FIXED標記的mmap()調(diào)用,然而這種方法的伸縮性不夠好,其問題在于其中每個mmap()調(diào)用都會創(chuàng)建一個獨立的內(nèi)核虛擬內(nèi)存區(qū)域 VMA 數(shù)據(jù)結(jié)構(gòu)。每個 VMA 的配置需要花費時間并且會消耗一些不可交換的內(nèi)核內(nèi)存。此外,大量的 VMA 會降低虛擬內(nèi)存管理器的性能。/proc/PID/maps中的一行表示一個 VMA。

Linux 提供的remap_file_pages()調(diào)用來在無需創(chuàng)建多個 VMA 的情況下創(chuàng)建非線性映射,具體如下:

使用mmap()創(chuàng)建一個映射

使用一個或者多個remap_file_pages()調(diào)用來調(diào)整內(nèi)存分頁和文件分頁之間的對應關系

#define_GNU_SOURCE
#include

intremap_file_pages(void*addr,size_tsize,intprot,size_tpgoff,intflags);

remap_file_pages()所做的工作是操作進程的頁表,僅適用于MAP_SHARED映射

pgoff和size參數(shù)標識了一個在內(nèi)存中的位置待改變的文件區(qū)域,pgoff參數(shù)指定了文件區(qū)域的起始位置,其單位是系統(tǒng)分頁代銷(sysconf(_SC_PAGESIZE)的返回值),size參數(shù)指定了文件區(qū)域的長度,其單位是字節(jié)

addr參數(shù)起兩個作用:

它標識了分頁需要調(diào)整的既有映射,addr必須是一個位于之前通過mmap()映射的區(qū)域中的地址

它指定了通過pgoff和size標識出的文件分頁所處的內(nèi)存地址

addr和size都應該是系統(tǒng)分頁大小的整數(shù)倍,如果不是,那么它們會被向下舍入到最近的分頁大小的整數(shù)倍

prot參數(shù)會被忽略,必須指定為 0

flags參數(shù)當前未被使用

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    87

    文章

    11350

    瀏覽量

    210477
  • 內(nèi)存
    +關注

    關注

    8

    文章

    3060

    瀏覽量

    74369
  • 文件
    +關注

    關注

    1

    文章

    571

    瀏覽量

    24831
  • 共享內(nèi)存

    關注

    0

    文章

    16

    瀏覽量

    8339
  • 進程
    +關注

    關注

    0

    文章

    204

    瀏覽量

    14002

原文標題:Linux應用開發(fā)之共享內(nèi)存

文章出處:【微信號:嵌入式應用研究院,微信公眾號:嵌入式應用研究院】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Linux下進程間如何實現(xiàn)共享內(nèi)存通信

    這次我們來講一下Linux進程通信中重要的通信方式:共享內(nèi)存作為Linux軟件開發(fā)攻城獅,進程間通信是必須熟練掌握的重要技能,而
    發(fā)表于 04-26 17:14 ?715次閱讀

    關于共享內(nèi)存的函數(shù)shmget()

    Linux進程間通信源碼剖析,共享內(nèi)存(shmget函數(shù)詳解)標簽: linuxstruct數(shù)據(jù)結(jié)構(gòu)存儲systemobject2010-12-22 23:18 8567人閱讀 評論(1
    發(fā)表于 09-24 15:47

    Linux進程間通信——使用共享內(nèi)存

    Linux進程間通信——使用共享內(nèi)存 圖文詳情見附件
    發(fā)表于 11-21 10:53

    請問IPC安裝完后的共享內(nèi)存是誰給劃定的?,LINUX和SYS/BISO的messageQ是怎樣實現(xiàn)共享內(nèi)存的同步的?

    一直沒看懂,IPC安裝完后的共享內(nèi)存是誰給劃定的,LINUX和SYS/BISO的messageQ是怎樣實現(xiàn)共享內(nèi)存的同步的(因為messag
    發(fā)表于 07-24 08:51

    linux如何共享內(nèi)存實驗

    更多技術(shù)文章地址:http://www.hqyj.com/news/emb211.htm?lcg-opendv  1.實驗目的  通過編寫共享內(nèi)存實驗,進一步了解使用共享內(nèi)存的具體步驟
    發(fā)表于 06-08 07:47

    linux中的共享內(nèi)存是指什么?共享內(nèi)存有哪些優(yōu)缺點

    什么是進程?進程有哪幾種狀態(tài)?共享內(nèi)存是指什么?共享內(nèi)存有哪些優(yōu)缺點?
    發(fā)表于 02-28 09:32

    Linux Ril中使用共享內(nèi)存交互相關資料分享

    1、移植RIL到ART-Smart共享內(nèi)存簡析本次移植的linux ril中,rild作為一個client與modem通過AT命令交互,同時也作為一個server與應用通信。在/li
    發(fā)表于 07-01 10:17

    進程間通信共享內(nèi)存

    8.5.1 共享內(nèi)存概述 可以說,共享內(nèi)存是一種最為高效的進程間通信方式。因為進程可以直接讀寫內(nèi)存,不需要任何數(shù)據(jù)的復制。為了在多個進程間交
    發(fā)表于 10-18 16:08 ?1次下載
    進程間通信<b class='flag-5'>之</b><b class='flag-5'>共享</b><b class='flag-5'>內(nèi)存</b>

    共享內(nèi)存IPC原理,Linux進程間如何共享內(nèi)存

    共享內(nèi)存是在內(nèi)存中單獨開辟的一段內(nèi)存空間,這段內(nèi)存空間有自己特有的數(shù)據(jù)結(jié)構(gòu),包括訪問權(quán)限、大小和最近訪問的時間等。該數(shù)據(jù)結(jié)構(gòu)定義如下
    的頭像 發(fā)表于 07-16 13:43 ?8692次閱讀
    <b class='flag-5'>共享</b><b class='flag-5'>內(nèi)存</b>IPC原理,<b class='flag-5'>Linux</b>進程間如何<b class='flag-5'>共享</b><b class='flag-5'>內(nèi)存</b>?

    你知道Linux共享內(nèi)存與tmpfs文件系統(tǒng)是什么樣?

    共享內(nèi)存主要用于進程間通信,Linux有兩種共享內(nèi)存(Shared Memory)機制
    發(fā)表于 05-04 17:33 ?2165次閱讀
    你知道<b class='flag-5'>Linux</b>的<b class='flag-5'>共享</b><b class='flag-5'>內(nèi)存</b>與tmpfs文件系統(tǒng)是什么樣?

    Linux IPC System V 共享內(nèi)存

    SHM_REMAP?(Linux-specific)表示如果要映射的共享內(nèi)存已經(jīng)有現(xiàn)存的內(nèi)存,那么就將舊的替換//掛接共享
    發(fā)表于 04-02 14:46 ?284次閱讀

    深入剖析Linux共享內(nèi)存原理

    不同進程之間進行通信,需要讓不同進程共享相同的物理內(nèi)存Linux通過? 共享內(nèi)存 ?來實現(xiàn)這個功能。下面先來介紹一下
    的頭像 發(fā)表于 10-30 09:52 ?2355次閱讀
    深入剖析<b class='flag-5'>Linux</b><b class='flag-5'>共享</b><b class='flag-5'>內(nèi)存</b>原理

    Linux系統(tǒng)的共享內(nèi)存的使用

    但有時候為了讓不同進程之間進行通信,需要讓不同進程共享相同的物理內(nèi)存,Linux通過 共享內(nèi)存 來實現(xiàn)這個功能。下面先來介紹一下
    的頭像 發(fā)表于 11-14 11:55 ?1374次閱讀

    Linux進程間共享內(nèi)存通信時如何同步?

    今天我們來講講進程間使用共享內(nèi)存通信時為了確保數(shù)據(jù)的正確,如何進行同步?
    的頭像 發(fā)表于 05-11 18:25 ?1622次閱讀

    Linux進程間如何實現(xiàn)共享內(nèi)存通信

    在上面的例程中,我們首先使用ftok()函數(shù)生成一個key值作為共享內(nèi)存的標識符。然后使用shmget()函數(shù)創(chuàng)建共享內(nèi)存區(qū)域,shmaddr指向
    發(fā)表于 06-19 09:55 ?661次閱讀