Linux作為一款廣泛應用於伺服器和嵌入式裝置的作業系統,佔據了越來越大的市場份額。在這些場景下,記憶體管理是至關重要的,因為它直接影響到系統的效能和穩定性,特別是對於程式設計師來說更是如此。對於想要在Linux平台上開發高效能應用程式的程式設計師來說,精通Linux記憶體管理是必須的。今天我們將介紹一篇文章,這篇文章是每個程式設計師都應該閱讀的:Linux記憶體管理。
對於記憶體部分需要知道:
先來看一些基本的知識,在流程看來,記憶體分為核心態和使用者態兩部分,經典比例如下:
#
從用戶態到內核態一般透過系統呼叫、中斷來實現。使用者態的記憶體被劃分為不同的區域用於不同的目的:
當然內核態也不會無差別地使用,所以,其分割如下:
下面來仔細看這些記憶體是如何管理的。
位址
在Linux內部的位址的對應過程為邏輯位址–>線性位址–>實體位址,實體位址最簡單:位址匯流排中傳送的數位訊號,而線性位址和邏輯位址所表示的則是一種轉換規則,線性位址規則如下:
這部分由MMU完成,其中涉及到主要的暫存器有CR0、CR3。機器指令中出現的是邏輯位址,邏輯位址規則如下:
在Linux中的邏輯位址等於線性位址,也就是說Inter為了相容把事情搞得很複雜,Linux簡化順便偷個懶。
記憶體管理的方式
#在系統boot的時候會去探測內存的大小和情況,在建立複雜的結構之前,需要用一個簡單的方式來管理這些內存,這就是bootmem,簡單來說就是位圖,不過其中也有一些優化的思路。
bootmem再怎麼優化,效率都不高,在要分配記憶體的時候畢竟是要去遍歷,buddy系統剛好能解決這個問題:在內部保存一些2的冪次大小的空閒記憶體片段,如果要分配3page,去4page的清單裡面取一個,分配3個之後將剩下的1個放回去,記憶體釋放的過程剛好是一個逆過程。用一個圖表來表示:
可以看到0、4、5、6、7都是正在使用的,那麼,1、2被釋放的時候,他們會合併嗎?
static inline unsigned long __find_buddy_index(unsigned long page_idx, unsigned int order) { return page_idx ^ (1
從上面這段程式碼可以看到,0、1是buddy,2、3是buddy,雖然1、2相鄰,但他們不是。記憶體碎片是系統運作的大敵,夥伴系統機制可以在一定程度上防止碎片~~另外,我們可以透過cat /proc/buddyinfo取得到各order中的空閒的頁數。
夥伴系統每次分配記憶體都是以頁(4KB)為單位的,但係統運作的時候使用的絕大部分的資料結構都是很小的,為一個小物件分配4KB顯然是不划算了。 Linux中使用slab來解決小物件的分配:
在運行時,slab向buddy「批發」一些內存,加工切塊以後「散賣」出去。隨著大規模多處理器系統和NUMA系統的廣泛應用,slab終於暴露出不足:
為了解決這些高手們開發了slub:改造page結構來削減slab管理結構的開銷、每個CPU都有一個本地活動的slab(kmem_cache_cpu)等。對於小型的嵌入式系統存在一個slab模擬層slob,在這種系統中它更有優勢。
小内存的问题算是解决了,但还有一个大内存的问题:用伙伴系统分配10 x 4KB的数据时,会去16 x 4KB的空闲列表里面去找(这样得到的物理内存是连续的),但很有可能系统里面有内存,但是伙伴系统分配不出来,因为他们被分割成小的片段。那么,vmalloc就是要用这些碎片来拼凑出一个大内存,相当于收集一些“边角料”,组装成一个成品后“出售”:
之前的内存都是直接映射的,第一次感觉到页式管理的存在:D 另外对于高端内存,提供了kmap方法为page分配一个线性地址。
进程由不同长度的段组成:代码段、动态库的代码、全局变量和动态产生数据的堆、栈等,在Linux中为每个进程管理了一套虚拟地址空间:
在我们写代码malloc完以后,并没有马上占用那么大的物理内存,而仅仅是维护上面的虚拟地址空间而已,只有在真正需要的时候才分配物理内存,这就是COW(COPY-ON-WRITE:写时复制)技术,而物理分配的过程就是最复杂的缺页异常处理环节了,下面来看!
缺页异常
在实际需要某个虚拟内存区域的数据之前,和物理内存之间的映射关系不会建立。如果进程访问的虚拟地址空间部分尚未与页帧关联,处理器自动引发一个缺页异常。在内核处理缺页异常时可以拿到的信息如下:
处理的流程如下:
发生缺页异常的时候,可能因为不常使用而被swap到磁盘上了,swap相关的命令如下:
swapon 开启swap swapoff 关闭swap /proc/sys/vm/swapiness 分值越大越积极使用swap,可以修改/etc/sysctl.conf中添加vm.swappiness=xx[1-100]来修改
如果内存是mmap映射到内存中的,那么在读、写对应内存的时候也会产生缺页异常。
在Linux中,内存管理是一个复杂的主题,但是如果程序员能够理解并充分利用它,他们可以极大地提高他们的程序的性能和可靠性。在本文中,我们介绍了Linux内存管理的基本知识、虚拟内存的概念、内存映射文件以及交换空间等。此外,我们还介绍了一些有助于程序员优化内存使用的技巧和工具。现在,不要再让程序的性能拖慢了你的项目,去掌握Linux内存管理吧!
以上是掌握Linux記憶體管理,讓你的程式效能再提升!的詳細內容。更多資訊請關注PHP中文網其他相關文章!