UNIX高級環境編程(15)進程和記憶體分配 < 故宮角樓 >

来源:http://www.cnblogs.com/suzhou/archive/2016/04/21/5418870.html
-Advertisement-
Play Games

故宮角樓是很多攝影愛好者常去的地方,夕陽餘輝下的故宮角樓平靜而安詳。首先,瞭解一下進程的基本概念,進程在記憶體中佈局和內容。此外,還需要知道運行時是如何為動態數據結構(如鏈表和二叉樹)分配額外記憶體的。一 進程1 進程和程式進程:是一個可執行程式的實例。程式:包含一系列信息的文件,這些信息描述瞭如何在運... ...


故宮角樓是很多攝影愛好者常去的地方,夕陽餘輝下的故宮角樓平靜而安詳。

故宮角樓

 

首先,瞭解一下進程的基本概念,進程在記憶體中佈局和內容。

此外,還需要知道運行時是如何為動態數據結構(如鏈表和二叉樹)分配額外記憶體的。

一 進程

1 進程和程式

進程:是一個可執行程式的實例。

程式:包含一系列信息的文件,這些信息描述瞭如何在運行時創建一個進程。包含如下信息:

  1. 二進位格式標識:如最常見的ELF格式。
  2. 機器語言指令:對程式演算法進行編碼。
  3. 程式入口地址:標識程式開始執行時的起始指令位置。
  4. 數據:程式文件包含的變數初始值和程式使用的字面常量值,如字元串。
  5. 符號表和重定位表:描述程式中函數和變數的位置及名稱。
  6. 共用庫和動態鏈接信息:程式文件中所包含的一些欄位,列出了程式運行時需要使用的共用庫,以及載入共用庫的動態鏈接器的路徑名。
  7. 其他信息。

進程的再定義:進程是由內核定義的抽象的實體,併為該實體分配用以執行程式的各項系統資源。

從內核的角度看,進程由用戶記憶體空間和一系列內核數據結構組成,其中用戶記憶體空間包含了程式代碼及代碼所使用的變數,而內核數據結構則用於維護進程狀態信息。

2 典型的進程記憶體佈局

NewImage

每個進程所分配的記憶體由很多部分組成,通常稱之為“段(segment)”。如上圖所示:

  1. 文本段:包含進程運行的程式機器語言指令。文本段具有隻讀屬性,因此多個進程可同時運行同一程式,共用文本段。
  2. 初始化數據段:包含顯式初始化的全局變數和靜態變數。當程式載入到記憶體時,從可執行文件中讀取這些變數的值。
  3. 未初始化數據段(BSS段,block started by symbol):包含了未進行顯式初始化的全局變數和靜態變數。程式啟動之前,系統將本段內所有記憶體初始化為0.所以又叫做零初始化數據段。
  4. 棧(stack):動態增長和收縮的段,由棧幀(stack frame)組成。系統會為每個當前調用的函數分配一個棧幀。棧幀中存儲了函數的局部變數、實參和返回值。
  5. 堆(heap):在運行時為變數動態進行記憶體分配的一塊區域。堆頂端成為程式中斷(program break)
將經過初始化的全局變數和靜態變數與未經過初始化的全局變數和靜態變數分開存放,其主要原因在於程式在磁碟上存儲時,沒有必要為未經過初始化的變數分配存儲空間。相反,可執行文件只需記錄未初始化數據段的位置及所需要大小,直到運行時再由程式載入器來分配這一空間。

需要註意一點時,該記憶體佈局的討論是在虛擬記憶體中的,並不是物理記憶體中的佈局。

在後面會專門討論虛擬記憶體的一些細節。

 

二 記憶體分配

1 在堆上分配記憶體

堆:一段長度可變的連續虛擬記憶體,始於進程的未初始化數據段末尾,隨著記憶體的分配和釋放而增減。將堆的當前記憶體頂部邊界稱為“程式中斷(program break)”

program break是一個非常重要的概念,因為分配和釋放記憶體的實際動作就是改變進程的program break位置。

program break的起始位置(堆的大小為0)位於未初始化數據段末尾之後。

細節:在分配新的記憶體後,program break位置升高,程式可以訪問新分配區域內的任何記憶體地址,而此時物理記憶體頁尚未分配。記憶體會在進程首次試圖訪問這些虛擬記憶體地址時自動分配新的物理記憶體頁。

函數malloc和free

malloc函數聲明

#include
void *malloc(size_t size); 

作用:在堆上分配參數size位元組大小的記憶體。

返回值:成功返回指向新分配記憶體起始地址的指針,失敗返回NULL

free函數聲明 

#include
void free(void *ptr);


作用:釋放ptr參數所指向的記憶體塊,該參數應該是之前由malloc或者其他記憶體分配函數之一所返回的地址。

需要註意的是:一般情況下,free並不降低program break的位置,而是將這塊記憶體增加到空閑記憶體列表中,供後續的malloc函數迴圈使用。因為:

  • 被釋放的記憶體塊通常位於堆的中間,而非堆的頂部,因而降低program break是不可能的。
  • 它最大限度地減少了內核調用調整program break系統調用的次數。
  • 通常程式會持有分配的記憶體或者反覆釋放和重新分配,而不是釋放所有記憶體再運行一段時間。

僅當堆頂空閑記憶體“足夠”大的時候,free函數的glibc實現會調用sbrk()來降低program break的地址,至於“足夠”與否則取決於malloc函數包行為的控制參數(128KB為典型值)。這減少了必須對sbrk()發起的調用次數。

malloc和free的實現

malloc()的實現

  1. 掃描之前由free()所釋放的空閑記憶體塊列表,以求找到尺寸大於或者等於要求的一塊記憶體
  2. 如果這一記憶體塊的尺寸正好與要求相當,就把它直接返回給調用者。
  3. 如果是一塊較大的記憶體,那麼將對其進行分割,在將一塊大小相當的記憶體返回給調用者的同時,把較小的那塊空閑記憶體塊保留在空閑列表。
  4. 如果在空閑記憶體列表中找不到足夠大的空閑記憶體塊,那麼malloc會調用sbrk()以分配更多的記憶體,並且malloc會分配出比所需位元組數更多的記憶體,將超出的部分置於空閑記憶體列表中。

free()的實現

首先先瞭解兩點:malloc返回的記憶體塊和空閑列表中的記憶體塊的結構

為了知道每一個記憶體塊的大小,當malloc分配記憶體塊時,會額外分配幾個位元組來存放記錄這塊記憶體大小的整數值。該整數位於記憶體塊的起始處,而實際返回給調用者的記憶體地址恰好位於這一長度記錄位元組之後。如下圖所示:

NewImage

為了管理空閑記憶體列表,free()會使用記憶體塊本身的空間來存放鏈表指針,將自身添加到列表中。如下圖所示:

NewImage

所以,在頻繁地分配和釋放記憶體之後,堆中的鏈表可能會變成下圖的樣子,空閑鏈表中的空閑記憶體會和已分配的在用記憶體混雜在一起。

NewImage

 

三 編程需要註意的事項

通過對記憶體相關知識更多的瞭解,在平時編程的時候,應更清楚為什麼我們需要遵守下麵的規則。

  1. 分配一塊記憶體後,不要改變這塊記憶體範圍外的任何內容。
  2. 釋放同一塊已分配記憶體超過一次是錯誤的。當兩次釋放同一塊記憶體時,常見的後果是導致不可預知的行為。
  3. 若非經由malloc函數包中函數所返回的指針,絕不能在調用free()函數使用。
  4. 如果需要反覆分配記憶體,那麼應當確保釋放所有已使用完畢的記憶體,不然將導致記憶體泄露。
 
雖然在我們平時的工作當中,可能涉及不到這麼底層的原理,但是通過對這些基本原理的瞭解,可以讓我們更加清除,我們寫代碼究竟在寫些什麼 :)

 

參考資料:

《Linux/Unix系統編程手冊(上冊)》 第6章,第7章 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • --模擬用戶登錄,該用戶ID為1010 fnd_global.apps_initialize(user_id => 1010, resp_id => 20420, resp_appl_id => 1); end; --獲取當時登錄的用戶的ID DECLARE l_user_id NUMBER :=  ...
  • 估計沒什麼價值,單純地記錄下時間,以便以後查看。 TMS320F28335 STM32f030 i3 4170 i3 4170 主頻 150MHz 48MHz 3.7GHZ 3.7GHZ IDE CCS6.0 Eclipse VS2015社區版 VS2015社區版 加速技術 rts2800_fpu3 ...
  • crontab參數: -u:幫助其他用戶建立或移除工作排程 -l:查閱crontab的工作內容 -r:移除所有的crontab的工作內容 -e:編輯crontab文件 每項工作有六個欄位: * * * * * * 分鐘 小時 日期 月份 周 指令 0-59 0-23 1-31 1-12 0-7 指令 ...
  • ARM9嵌入式學習筆記(1) Linux命令 實驗1 1 2 Linux常見命令使用 1. 添加用戶 ; 設置賬戶密碼 ; 切換用戶 2. 關機命令 3. 拷貝命令 cp /home/test /tmp/ //將test文件拷貝到tmp目錄下 cp r /home/dir1 /tmp/ //將目錄d ...
  • 項目檢出 如果你的git還沒有代碼倉庫,可以用過git的代碼倉庫頁面新建一個你的倉庫 創建git上的倉庫後,我們還需要建立本地的倉庫,所以打開Mac終端,建立本地倉庫文件夾(這裡我用HelloC),然後進入到新建的文件夾下 mkdir HelloC cd HelloC 在git頁面中,複製你的倉庫地 ...
  • rewrite模塊名:ngx_http_rewrite_module預設自動被編譯 指令:rewrite regex replacement [flag] regex :正則表達式,用於匹配用戶請求的uri replacement:重寫後的結果 flag: last:重寫完成之後停止對當前uri的進 ...
  • 1、安裝svn客戶端 1.1、使用命令安裝 1)CentOS 2)ubuntu 1.2、源碼安裝 http://www.cnblogs.com/fengbohello/p/4142810.html 2、開啟svn服務進程 2.1、我的習慣是把代碼倉庫放在/opt/svn目錄下,所以先創建目錄/opt ...
  • 1.Gnu/Linux是一個基於POSIX和UNIX的多用戶多任務 支持多線程多CPU的類UNIX的操作系統. 繼承了UNIX以網路為核心的設計思想 是性能穩定的多用戶網路操作系統. 1991年10月5日Linus Torvalds在usenet的comp.os.minix新聞組中發佈了第一個Lin ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...