一個系統中的進程是與其他進程共享CPU和主存資源的。隨著對CPU需求的增長,進程以某種合理的平滑的方式慢了下來。這里給大家分享一些關于全面解析虛擬內存,希望對大家能有所幫助。
虛擬內存空間
1.保留區(受保護的地址)
保留區即為受保護的地址,大小為128M,位于虛擬地址空間的最低部分,未賦予物理地址。任何對它的引用都是非法的,用于捕捉使用空指針和小整型值指針引用內存的異常情況。
它并不是一個單一的內存區域,而是對地址空間中受到操作系統保護而禁止用戶進程訪問的地址區域的總稱。大多數操作系統中,極小的地址通常都是不允許訪問的,如NULL。C語言將無效指針賦值為0也是出于這種考慮,因為0地址上正常情況下不會存放有效的可訪問數據。。
2.代碼段
代碼段也稱正文段或文本段,通常用于存放程序執行代碼(即CPU執行的機器指令)。一般C語言執行語句都編譯成機器代碼保存在代碼段。通常代碼段是可共享的,因此頻繁執行的程序只需要在內存中擁有一份拷貝即可。代碼段通常屬于只讀,以防止其他程序意外地修改其指令(對該段的寫操作將導致段錯誤)。某些架構也允許代碼段為可寫,即允許修改程序。
3.數據段(.data段)
數據段通常用于存放程序中已初始化的全局變量和靜態局部變量。數據段屬于靜態內存分配(靜態存儲區),可讀可寫。由于全局變量未初始化時,其默認值為0,因此值為0的全局變量位于.bbs段(不位于數據段)。對于未初始化的局部變量,其值是不可預測的。注意:在代碼段和數據段之間還包括其它段:只讀數據段和符號段等。
4. .bbs段
該段用于存放未初始化的全局變量和靜態局部變量,包括值為0的全局變量。 數據段和.bbs段又稱為全局數據區,前者初始化,后者未初始化。
ELF段包括:代碼段、其它段(在.data段和.text段之間,包括只讀數據段和符號段等)、.data段(數據段)和.bbs段,都屬于可執行程序部分。
5.堆空間
new( )和malloc( )函數分配的空間就屬于堆空間。
分配的堆內存是經過字節對齊的空間,以適合原子操作。堆管理器通過鏈表管理每個申請的內存,由于堆申請和釋放是無序的,最終會產生內存碎片。堆內存一般由應用程序分配釋放,回收的內存可供重新使用。若程序員不釋放,程序結束時操作系統可能會自動回收。
堆的末端由break指針標識,當堆管理器需要更多內存時,可通過系統調用brk()和sbrk()來移動break指針以擴張堆,一般由系統自動調用。
使用堆時經常出現兩種問題:1) 釋放或改寫仍在使用的內存(“內存破壞”);2)未釋放不再使用的內存(“內存泄漏”)。當釋放次數少于申請次數時,可能已造成內存泄漏。泄漏的內存往往比忘記釋放的數據結構更大,因為所分配的內存通常會圓整為下個大于申請數量的2的冪次(如申請212B,會圓整為256B)。
6.內存映射段(共享庫)
內核將硬盤文件的內容直接映射到內存, 任何應用程序都可通過Linux的mmap()系統調用請求這種映射。內存映射是一種方便高效的文件I/O方式, 因而被用于裝載動態共享庫。如C標準庫函數(fread、fwrite、fopen等)和Linux系統I/O函數,它們都是動態庫函數,其中C標準庫函數都被封裝在了/lib/libc.so庫文件中,都是二進制文件。這些動態庫函數都是與位置無關的代碼,即每次被加載進入內存映射區時的位置都是不一樣的,因此使用的是其本身的邏輯地址,經過變換成線性地址(虛擬地址),然后再映射到內存。而靜態庫不一樣,由于靜態庫被鏈接到可執行文件中,因此其位于代碼段,每次在地址空間中的位置都是固定的。
7.棧空間
用于存放局部變量(非靜態局部變量,C語言稱為自動變量),分配存儲空間時從上往下。
虛擬內存實現方式
頁面和頁框
我們來打個比方,假設你現在有一臺32KB內存的電腦,虛擬內存是64KB。首先我們先將64KB的虛擬內存切個片,一個片大小為4KB,所以總共切了16片。同時,把32KB的物理內存也按4KB的切片,總共切了8片。那么我們就稱虛擬內存的一個片叫做頁面,物理內存的一個片叫做頁框。
頁表
同學們可能已經猜到了,沒錯,虛擬內存和物理內存之間是有一個映射關系的。這個映射該怎么實現呢,這就需要我們頁表的登場啦!頁表中維護著頁表和頁框的對應關系。舉個栗子,一個地址為0x0010000000000100的16位地址。16位地址可拆分為兩部分,前4位和后12位。前4位對應著16個虛擬頁表的號牌用于在頁表中尋找對應的頁框號,后12位用于頁內偏址。0010即是2號,我們在頁表中查找2號選手對應的頁框,假設是100。那么我們虛擬地址所對應的物理地址即可得出,為100+之前的后12位頁內偏移地址,即0x100000000000100。
不過畢竟頁面比頁框為16:8,那么肯定會有一部分的頁面沒有所對應的頁框,如果我們的虛擬地址就在這些頁面中我們該怎么辦呢?
缺頁中斷
沒錯,如果我們的虛擬地址所在頁面沒有對應的頁框,那么系統會產生一個缺頁中斷。缺頁中斷使CPU停下手頭的工作,轉而去尋找一個使用最少的一個頁框,將其寫入到磁盤中(如果頁框范圍內地址的內容有改變的話,沒有改變則不需要寫入磁盤)。然后修改將頁面指向該頁框,修改映射關系,至此缺頁中斷處理結束。CPU繼續執行之前的工作。
TLB
到這里,虛擬內存已經可以完整的映射到物理內存了,但還有一些問題。那就是速度問題。我們設想一下,如果把頁表存儲在進程中,那么每次CPU都得進入內存中查詢,非常的影響速度。那我們如果設置一個寄存器在CPU中,那速度不就很快了么?確實這樣CPU的訪問速度會非常的快,但是每次的進程切換,都會有新的頁表載入該寄存器中,同樣非常影響速度。那我們就沒有辦法了么?根據計算機科學家的統計,其實有一些頁面映射是非常頻繁的,而剩余的映射則非常少,那么我們就可以將這些映射最頻繁的頁面放入CPU寄存器中,而這個CPU寄存器我們就叫他TLB。
虛擬內存原理
內存在計算機中的作用很大,電腦中所有運行的程序都需要經過內存來執行,如果執行的程序很大或很多,就會導致內存消耗殆盡。為了解決這個問題,Windows中運用了虛擬內存技術,即拿出一部分硬盤空間來充當內存使用,當內存占用完時,電腦就會自動調用硬盤來充當內存,以緩解內存的緊張。舉一個例子來說,如果電腦只有128MB物理內存的話,當讀取一個容量為200MB的文件時,就必須要用到比較大的虛擬內存,文件被內存讀取之后就會先儲存到虛擬內存,等待內存把文件全部儲存到虛擬內存之后,跟著就會把虛擬內里儲存的文件釋放到原來的安裝目錄里了。
當系統運行時,先要將所需的指令和數據從外部存儲器(如硬盤、軟盤、光盤等)調入內存中,CPU再從內存中讀取指令或數據進行運算,并將運算結果存入內存中,內存所起的作用就像一個“二傳手”的作用。當運行一個程序需要大量數據、占用大量內存時,內存這個倉庫就會被“塞滿”,而在這個“倉庫”中總有一部分暫時不用的數據占據著有限的空間,所以要將這部分“惰性”的數據“請”出去,以騰出地方給“活性”數據使用。這時就需要新建另一個后備“倉庫”去存放“惰性”數據。由于硬盤的空間很大,所以微軟Windows操作系統就將后備“倉庫”的地址選在硬盤上,這個后備“倉庫”就是虛擬內存。在默認情況下,虛擬內存是以名為Pagefile.sys的交換文件保存在硬盤的系統分區中。
虛擬內存相關文章:
★ 如何合理設置電腦虛擬內存,提高電腦運行速度
★ 提高內存使用效能的幾種方法
★ 介紹幾個妙招加快內存運行速度
★ 全面釋放C盤被強行占用的空間
★ 讓你的電腦一點都不卡
★ 電腦系統資源不足及解決辦法
★ 電腦技巧
★ 電腦技巧
★ 電腦死機的常見原因
★ 關于電腦死機的原因及解決方法分享
上一篇:操作系統內存管理知識
下一篇:操作系統內存管理