1. 程式人生 > >malloc原理和記憶體碎片化

malloc原理和記憶體碎片化

當一個程序發生缺頁中斷的時候,程序會陷入核心態,執行以下操作: 
1、檢查要訪問的虛擬地址是否合法 
2、查詢/分配一個物理頁 
3、填充物理頁內容(讀取磁碟,或者直接置0,或者啥也不幹) 
4、建立對映關係(虛擬地址到實體地址) 
重新執行發生缺頁中斷的那條指令 
如果第3步,需要讀取磁碟,那麼這次缺頁中斷就是majflt,否則就是minflt。 

記憶體分配的原理

從作業系統角度來看,程序分配記憶體有兩種方式,分別由兩個系統呼叫完成:brk和mmap(不考慮共享記憶體)。

1、brk是將資料段(.data)的最高地址指標_edata往高地址推;

2、mmap是在程序的虛擬地址空間中(堆和棧中間,稱為檔案對映區域的地方)找一塊空閒的虛擬記憶體

     這兩種方式分配的都是虛擬記憶體,沒有分配實體記憶體在第一次訪問已分配的虛擬地址空間的時候,發生缺頁中斷,作業系統負責分配實體記憶體,然後建立虛擬記憶體和實體記憶體之間的對映關係。

在標準C庫中,提供了malloc/free函式分配釋放記憶體,這兩個函式底層是由brk,mmap,munmap這些系統呼叫實現的。


下面以一個例子來說明記憶體分配的原理:

情況一、malloc小於128k的記憶體,使用brk分配記憶體,將_edata往高地址推(只分配虛擬空間,不對應實體記憶體(因此沒有初始化),第一次讀/寫資料時,引起核心缺頁中斷,核心才分配對應的實體記憶體,然後虛擬地址空間建立對映關係),如下圖:


1、程序啟動的時候,其(虛擬)記憶體空間的初始佈局如圖1所示。       其中,mmap記憶體對映檔案是在堆和棧的中間(例如libc-2.2.93.so,其它資料檔案等),為了簡單起見,省略了記憶體對映檔案。       _edata指標(glibc裡面定義)指向資料段的最高地址。 
2、
程序呼叫A=malloc(30K)以後,記憶體空間如圖2:       malloc函式會呼叫brk系統呼叫,將_edata指標往高地址推30K,就完成虛擬記憶體分配。       你可能會問:只要把_edata+30K就完成記憶體分配了?       事實是這樣的,_edata+30K只是完成虛擬地址的分配,A這塊記憶體現在還是沒有物理頁與之對應的,等到程序第一次讀寫A這塊記憶體的時候,發生缺頁中斷,這個時候,核心才分配A這塊記憶體對應的物理頁。也就是說,如果用malloc分配了A這塊內容,然後從來不訪問它,那麼,A對應的物理頁是不會被分配的。 
3、
程序呼叫B=malloc(40K)以後,記憶體空間如圖3。

情況二、malloc大於128k的記憶體,使用mmap分配記憶體,在堆和棧之間找一塊空閒記憶體分配(對應獨立記憶體,而且初始化為0),如下圖:

4、程序呼叫C=malloc(200K)以後,記憶體空間如圖4:       預設情況下,malloc函式分配記憶體,如果請求記憶體大於128K(可由M_MMAP_THRESHOLD選項調節),那就不是去推_edata指標了,而是利用mmap系統呼叫,從堆和棧的中間分配一塊虛擬記憶體。       這樣子做主要是因為::       brk分配的記憶體需要等到高地址記憶體釋放以後才能釋放(例如,在B釋放之前,A是不可能釋放的,這就是記憶體碎片產生的原因,什麼時候緊縮看下面),而mmap分配的記憶體可以單獨釋放。 當然,還有其它的好處,也有壞處,再具體下去,有興趣的同學可以去看glibc裡面malloc的程式碼了。 
5、程序呼叫D=malloc(100K)以後,記憶體空間如圖5;
6、程序呼叫free(C)以後,C對應的虛擬記憶體和實體記憶體一起釋放。

7、程序呼叫free(B)以後,如圖7所示:         B對應的虛擬記憶體和實體記憶體都沒有釋放,因為只有一個_edata指標,如果往回推,那麼D這塊記憶體怎麼辦呢當然,B這塊記憶體,是可以重用的,如果這個時候再來一個40K的請求,那麼malloc很可能就把B這塊記憶體返回回去了。 
8、程序呼叫free(D)以後,如圖8所示:         B和D連線起來,變成一塊140K的空閒記憶體。 9、預設情況下:        當最高地址空間的空閒記憶體超過128K(可由M_TRIM_THRESHOLD選項調節)時,執行記憶體緊縮操作(trim)。在上一個步驟free的時候,發現最高地址空閒記憶體超過128K,於是記憶體緊縮,變成圖9所示。

相關推薦

malloc原理記憶體碎片

當一個程序發生缺頁中斷的時候,程序會陷入核心態,執行以下操作: 1、檢查要訪問的虛擬地址是否合法  2、查詢/分配一個物理頁  3、填充物理頁內容(讀取磁碟,或者直接置0,或者啥也不幹)  4、建立對映關係(虛擬地址到實體地址) 重新執行發生缺頁中斷的那條指令 如果第3步

ThreadLocal實現原理記憶體洩漏問題

1.概述 ThreadLocal不是為了解決多執行緒訪問共享變數,而是為每個執行緒建立一個單獨的變數副本,變數在多執行緒環境下訪問(通過get或set方法訪問)時能保證各個執行緒裡的變數相對獨立於其他執行緒內的變數,ThreadLocal例項通常來說都是private static型別。

避免實體記憶體碎片

在2.6.20-rc6中,mel Gorman提交了的patch引入了ZONE_MOVABLE,引入這個pseudo zone的目的是為了防止zone記憶體碎片化 ZONE_MOVABLE表示這個zone僅能被帶有__GFP_HIGHMEM和__GFP_MOVABLE標誌的

java 中幾種map的儲存原理記憶體佔用情況

Map,即對映,也稱為 鍵值對,有一個 Key, 一個 Value 。 比如 Groovy 語言中,  def  map = ['name' : 'liudehua', 'age' : 50 ] ,則 map[ 'name' ]  的值是 'liudehua'。  那

c++記憶體洩漏記憶體碎片的問題

1.記憶體洩漏的定義    一般我們常說的記憶體洩漏是指堆記憶體的洩漏。堆記憶體是指程式從堆中分配的,大小任意的(記憶體塊的大小可以在程式執行期決定),使用完後必須顯示釋放的記憶體。應用程式一般使用malloc,realloc,new等函式從堆中分配到一塊記憶體,使用

圖解記憶體池內部結構,看它是如何克服記憶體碎片的?

記憶體是軟體系統必不可少的物理資源,精湛的記憶體管理技術是確保記憶體使用效率的關鍵,也是進階高階研發的必備技巧。為提高記憶體分配效率,_Python_ 內部做了很多殫心竭慮的優化,從中我們可以獲得一些啟發。 開始研究 _Python_ 記憶體池之前,我們先大致瞭解下 _Python_ 記憶體管理層次:

Asp.net相關知識經驗的碎片記錄

class xquery 配置 lte 方案 字符 慎用 code run 1、解決IIS7.0下“HTTP 錯誤 404.15 - Not Found 請求篩選模塊被配置為拒絕包含的查詢字符串過長的請求”問題 方案1:在程序的web.config中system.web節點

Android外掛原理實踐 (四) 之 合併外掛中的資源

我們繼續來學習Android外掛化相關知識,還是要圍繞著三個根本問題來展開。在前面兩章中已經講解過第一個根本問題:在宿主中如何去載入外掛以及呼叫外掛中類和元件程式碼。Demo中使用了Service來演示,因為還沒有解決載入外掛中資源的問題,用Activity不好展示。所以本文將要從資源的載入機制

程序間通訊——共享記憶體(Shared Memory)簡易原理建立_獲得函式

共享記憶體是System V版本的最後一個程序間通訊方式。共享記憶體,顧名思義就是允許兩個不相關的程序訪問同一個邏輯記憶體,共享記憶體是兩個正在執行的程序之間共享和傳遞資料的一種非常有效的方式。不同程序之間共享的記憶體通常為同一段實體記憶體。程序可以將同一段實體記憶體連線到他們自己的地址空間中,所有

Android外掛原理實踐 (七) 之 專案實踐

我們在前面一系列文章中已經介紹完了外掛化原理以及三個根本問題的解決方案,本文主要就是作為前面幾篇文章的一個總結,通過專案實踐將前面的知識點串起來使完成一個入門級簡單的外掛化工程以及在實際外掛化開發中遇到的一些總結。 實踐 我們先通過Android Studio建立一個工程,工程中包括了兩

NCC(Normalized Cross Correlation)歸一互相關原理C++程式碼實現

NCC(Normalized Cross Correlation)歸一化互相關 影象匹配指在已知目標基準圖的子圖集合中,尋找與實時影象最相似的子圖,以達到目標識別與定位目的的影象技術。主要方法有:基於影象灰度相關方法、基於影象特徵方法、基於神經網路相關的人工智慧

玩轉OpenStack--6>CPU 記憶體虛擬化原理

玩轉OpenStack--6>CPU 和記憶體虛擬化原理 前面我們成功地把 KVM 跑起來了,有了些感性認識,這個對於初學者非常重要。不過還不夠,我們多少得了解一些 KVM 的實現機制,這對以後的工作會有幫助。 CPU 虛擬化 KVM 的虛擬化是需要 CPU 硬體

【譯】JavaScript的工作原理記憶體管理4種常見的記憶體洩漏

該系列的第一篇文章重點介紹了引擎,執行時和呼叫堆疊的概述。第二篇文章深入剖析了Google的V8 JavaScript引擎,並提供了關於如何編寫更好的JavaScript程式碼的一些提示。 在第三篇文章中,我們將討論另一個越來越被開發人員忽視的關鍵主題,因為日常使用的程式語言(記憶體管理)越來越成熟和複雜。

C++中虛擬函式工作原理 虛 繼承類的記憶體佔用大小計算

                      虛擬函式的實現要求物件攜帶額外的資訊,這些資訊用於在執行時確定該物件應該呼叫哪一個虛擬函式。典型情況下,這一資訊具有一種被稱為 vptr(virtual table pointer,虛擬函式表指標)的指標的形式。vptr 指向一個被稱為 vtbl(virtual t

GeoHash原理視覺顯示

  最近在做附近定位功能的產品,geohash是一個非常不錯的實現方式。查詢資料,發現阿里的這篇文章講解的很好。但文中並沒有給出geohash顯示的工具。無奈,也沒有查到類似的。只好自己簡單顯示一下,方便自己理解。   專案地址:  https://github.

C/C++快速讀寫磁碟資料的方法-塊讀取/非同步/優化分析演算法/記憶體檔案對映的原理使用

快速讀寫磁碟資料的方法: 1.塊讀取:一下子將資料讀取到記憶體的(無論是文字還是二進位制),而不是一行行的讀取。 2.非同步的IO,建立多執行緒,或者使用重疊IO,IO複用,非同步的事件回撥通知機制(可以用事件物件,訊號驅動來實現)。 3.優化分析檔案的演算法和儘量延後分析,分析演算法裡

【Flink原理應用】:Flink高效的記憶體管理

1. 前言 如今,大資料領域的開源框架(Hadoop,Spark,Storm)都使用的 JVM,當然也包括 Flink。基於 JVM 的資料分析引擎都需要面對將大量資料存到記憶體中,這就不得不面對 JVM 存在的幾個問題: Java 物件儲存密度低。一個只包含 boolea

演示記憶體碎片原理的好圖

a,b,c,d.....分別代表時間,從最早往後面。 白色區域表示空閒記憶體。灰色區域表示程序佔據的記憶體,藍色區域表示作業系統佔據的記憶體,這部分是固定好的。 看記憶體碎片的發展過程: a圖表示,假設記憶體目前有56m的記憶體空間。到了b圖,有個程序佔了20m的記憶體,現在還剩下36m了。

Android 元件開發原理配置

在Application的不斷髮展過程中,我們開發者要不斷地增加新特性。更多的程式碼就意味著更長的build時間和更長的增量build時間。在工程較大的專案中,build時間要佔到10%~15%的工作時間。這不僅是浪費時間,也是測試驅動工作方式(TDD)比較困難的原因。

深入學習JVM記憶體設定原理調優

一、設定JVM記憶體設定 1. 設定JVM記憶體的引數有四個: -Xmx   Java Heap最大值,預設值為實體記憶體的1/4,最佳設值應該視實體記憶體大小及計算機內其他記憶體開銷而定; -Xms   Java Heap初始值,Server端JVM最好將-Xms和-Xmx設為相同值,開發測試機J