C/C++|malloc分配內存詳解

看本節前,希望讀者有linux內存分布的基本概念,可以閱讀這篇文章:
進程虛擬地址空間和函數調用棧

在本節中希望讀者可以一口氣閱讀完所有內容。
本博客內容全部來自小林coding:malloc 是如何分配內存的?
這里僅為筆記記錄。

文章目錄

  • malloc是如何分配內存的?
    • 通過 brk() 系統調用
    • 通過mmap()申請內存
  • ??malloc()分配的是物理內存嗎?
  • ??malloc()竟然會構建內存池!
  • free釋放內存,會馬上歸還給操作系統嗎?
  • 即然 brk 那么好,為什么不全部使用brk來分配?

malloc是如何分配內存的?

首先我們要明確一點,malloc() 并不是系統調用,而是 C 庫里的函數,用于動態分配內存。
同時調用mlloc也并不一定會陷入內核態。

malloc申請內存會以兩種方式向操作系統申請堆內存:

  • 通過 brk() 系統調用從堆分配內存
  • 通過 mmap() 系統調用在文件映射區域分配內存

通過 brk() 系統調用

brk()的實現方式就是將「堆頂」指針向高地址移動,獲得新的內存空間。

并且malloc()源碼中默認定義了閾值,如果用戶分配內存小于128KB則通過brk()申請內存。

通過mmap()申請內存

mmap() 系統調用通過「私有匿名映射」的方式,在文件映射區分配一塊內存,也就是從文件映射區“偷”了一塊內存。如下圖:

在操作文件時,我們一般通過 open() 打開文件,然后使用 mmap() 將文件內容直接映射到虛擬內存上,這樣我們就可以像操作內存一樣操作文件的內容,這一塊區域就是文件映射區。

如果用戶分配的內存大于 128 KB,則通過 mmap() 申請內存;

不同的gilbc版本定義的閾值也是不同的

??malloc()分配的是物理內存嗎?

這個答案很明顯,malloc分配的是虛擬內存,但是下一句話更加重要!

如果分配后的虛擬內存沒有被訪問的話,虛擬內存是不會映射到物理內存的,這樣就不會占用物理內存了。

  1. 在訪問已分配的虛擬地址空間的時候,操作系統通過查找頁表,發現虛擬內存對應的頁沒有在物理內存中;
  2. 就會觸發缺頁中斷
  3. 然后操作系統會建立虛擬內存和物理內存之間的映射關系

??malloc()竟然會構建內存池!

malloc() 在分配內存的時候,會預分配更大的空間作為內存池

也就是說,當我們調用brk()系統調用申請堆內存,仍然會為我們分配超過128KB字節的內存。即使你 malloc()的內存遠小于128k也是一樣。

為什么malloc要使用內存池來進行管理呢?

  1. 提高效率:內存池預先分配一大塊內存,然后在需要時從中分配小塊,減少了頻繁調用系統級別的內存分配開銷(brk()\mmap())「每次調用 sbrk 或 mmap 時,程序需要從用戶態切換到內核態,這個切換過程本身就有一定的開銷;陷入內核態也涉及到了系統需要更新內存管理的數據結構,如頁表和內存分配表,需要額外的時間;再一個,為了保證內存分配的線程安全,內核需要處理同步和鎖管理,增加了開銷」。

現在你還覺得每次調用malloc都會陷入內核態嗎?

  1. 減少了內存碎片,內存池通過組織和管理內存塊,能更好地利用內存空間,減少內存碎片,提高內存使用率。
  2. 快速釋放和重用,跟第一點一樣,在池內管理,避免了系統調用的高開銷。

free釋放內存,會馬上歸還給操作系統嗎?

看了malloc竟然開辟了內存池,你覺得free會把內存歸還給操作系統嗎?

這里直接說結論:

通過 free 釋放內存后,堆內存還是存在的,并沒有歸還給操作系統。當然,當進程退出后,操作系統就會回收進程的所有資源。


但是!

如果我們使用mmap方式申請內存,free釋放內存后就會馬上歸還操作系統。

總結:

  • malloc 通過 brk() 方式申請的內存,free 釋放內存的時候,并不會把內存歸還給操作系統,而是緩存在 malloc 的內存池中,待下次使用;
  • malloc 通過 mmap() 方式申請的內存,free 釋放內存的時候,會把內存歸還給操作系統,內存得到真正的釋放。

即然 brk 那么好,為什么不全部使用brk來分配?

我們考慮這樣一個場景:

如果我們連續申請了 10k,20k,30k 這三片內存,如果 10k 和 20k 這兩片釋放了,變為了空閑內存空間,如果下次申請的內存小于 30k,那么就可以重用這個空閑內存空間。

但是如果下次申請的內存大于 30k,沒有可用的空閑內存空間,必須向 OS 申請,實際使用內存繼續增大。

因此,隨著系統頻繁地 malloc 和 free ,尤其對于小塊內存,堆內將產生越來越多不可用的碎片,導致“內存泄露”。而這種“泄露”現象使用 valgrind 是無法檢測出來的

所以,malloc 實現中,充分考慮了 brk 和 mmap 行為上的差異及優缺點,默認分配大塊內存 (128KB) 才使用 mmap 分配內存空間。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/15970.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/15970.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/15970.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python-圖片旋轉360,保存對應圖片

#Author :susocool #Creattime:2024/5/25 #FileName:turn360 #Description: 會旋轉指定的圖像文件360度,并將每個旋轉后的圖像保存到指定目錄,文件名以旋轉角度命名。 from PIL import Imagedef rotate_and_save(image_path, output_dir) :# …

Linux/Ubuntu 中安裝 ZeroTier,實現內網穿透,2分鐘搞定

相信很多人都有遠程連接家中設備的需求,如遠程連接家中的NAS、Windows等服務,所以會涉及到一個內網穿透工具的使用,如果沒有公網IP的情況下,推薦大家使用ZeroTier,這是一款強大的內網穿透工具。 mac和windows版的操作…

Nginx-狂神說

Nginx概述 公司產品出現瓶頸? 我們公司項目剛剛上線的時候,并發量小,用戶使用的少,所以在低并發的情況下,一個jar包啟動應用就夠了,然后內部tomcat返回內容給用戶。 但是慢慢的,使用我們平臺…

HTTP 各版本差異

http1.0 它的特點是每次請球和響應完畢后都會銷毀TCP 連接。同時規走前一個響應完成后才發送下一個請求。這樣做有兩個問題: 無法復用連接了。 每次請求都要創建新的TCP連接,完成三次握手和四次揮手。網絡利用率低 隊頭阻塞 如果前一個請求被某種原因阻…

K8S認證|CKA題庫+答案| 13. sidecar 代理容器日志

目錄 13、使用 sidecar 代理容器日志 CKA v1.29.0模擬系統免費下載試用: 題目: 開始操作: 1)、切換集群 2)、生成yaml文件 3)、官網找模板 4)、編輯yaml文件 5)、應用yaml…

車載電子電器架構 —— 智能座艙技術

車載電子電器架構 —— 智能座艙技術 我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 屏蔽力是信息過載時代一個人的特殊競爭力,任何消耗你的…

qt multiple definition of 報錯解決

qt編譯報了很多錯, multiple definition of xxx 原來一維設計文件ui 的問題 后來發現是pro中頭文件和cpp文件重寫了,導致重復編譯報的錯 解決方法:把重復的頭文件和cpp文件刪了就可以了。

如何解決0.1+0.2!=0.3的問題

var x 0.1; var y 0.2; var z x y // z 的結果為 0.30000000000000004 if (z 0.3) // 返回 false 可以用整數的乘除法來解決 var z (x * 10 y * 10) / 10; // z 的結果為 0.3

GEO數據挖掘-GEO背景知識+表達芯片分析思路

From生物技能樹 GEO數據挖掘第一節 (pipeline) 文章目錄 1.圖表分析2.GEO背景介紹及分析思路3.代碼分析流程4.復雜數據分析理論知識1.數據從哪里來2.有什么類型的數據可挖掘3.如何篩選基因(分析方法)在這里插入圖片描述 圖表介紹1…

Jenkins + github 自動化部署配置

1 Jenkins安裝 AWS EC2安裝Jenkins:AWS EC2 JDK11 Jenkins-CSDN博客 AWS EC2上Docker安裝Jenkins:https://blog.csdn.net/hhujjj2005/article/details/139078402 2 登錄jenkins http://192.168.1.128:8080/ $ docker exec -it d1851d9e3386 /bin/ba…

Multi-objective reinforcement learning approach for trip recommendation

Multi-objective reinforcement learning approach for trip recommendation A B S T R A C T 行程推薦是一項智能服務,為游客在陌生的城市提供個性化的行程規劃。 它旨在構建一系列有序的 POI,在時間和空間限制下最大化用戶的旅行體驗。 將候選 POI 添…

【Shell】sed編輯器實例

sed是用來解析和轉換文本的工具,它使用簡單,是簡潔的程序設計語言。 sed編輯器 (一) sed編輯器基礎1. 簡介2. sed的模式空間 (二)基本的sed編輯命令(三)sed命令實例1. 向文件中添加或…

MFC GDI 繪圖模式、映射模式、畫筆、筆、字體

一 GDI 繪圖模式(RoP2 Mode) 在使用VC MFC進行圖形程序編程時,常會用到GDI繪圖指令,而要做到繪圖時有橡皮筋動態效果,就需設置GDI繪圖模式。GDI繪圖模式有多種,如下: 常用R2_NOT模式來實…

Linux|操作系統|如何下載各個版本的centos操作系統

前言: centos做為一個現在比較常用的Linux社區版本,還是比較受歡迎的,那么,如何下載centos的安裝包,也就是centos的操作系統呢? 首先,我們應該知道硬件底層有aarch64,ppc64&#x…

【限免】短時傅里葉變換時頻分析【附MATLAB代碼】

來源:微信公眾號:EW Frontier 簡介 一種能夠同時對信號時域和頻域分析的方法——短時傅里葉變換(STFT),可以在時頻二維角度準確地描述信號 的時間、頻域的局部特性,與其他算法不同,通過該算法可…

【Elasticsearch】Centos7安裝Elasticsearch、kibana、IK分詞

目錄 本文安裝包下載地址注意安裝elasticsearch1.上傳文件2.解壓elasticsearch-6.3.1.tar.gz3.開啟遠程連接權限4.修改其他配置[root用戶操作]5.重啟虛擬機6.啟動es7.外部訪問 安裝kibana-61.解壓2.配置3.啟動kibana4.訪問5.在開發工具中做數據的增刪改查操作 安裝IK分詞1.wind…

簡述什么是Vue的自定義指令

Vue的自定義指令是Vue框架提供的一種擴展機制,允許開發者注冊自己的指令,從而封裝一些DOM操作或添加額外的功能。這些自定義指令可以在Vue模板中像內置指令(如v-for、v-if等)一樣使用,但提供了更大的靈活性和自定義性。…

QML與C++交互的兩種注冊方法比較(rootContext 和 qmlRegisterType)

在main.cpp實例化對象調用的過程中&#xff0c;注冊是常見的操作之一&#xff0c;目前接觸到的方法有兩種&#xff0c;兩者的目的和使用方式是不同的&#xff0c;通過代碼可以直觀的 看出來&#xff1a; int main(int argc, char *argv[]) { #if QT_VERSION < QT_VERSION_C…

軟件安全復習

文章目錄 第一章 軟件安全概述1.1 信息定義1.2 信息的屬性1.3 信息安全1.4 軟件安全1.5 軟件安全威脅及其來源1.5.1 軟件缺陷與漏洞1.5.1.1 軟件缺陷1.5.1.2 漏洞1.5.1.3 軟件漏洞1.5.1.4 軟件缺陷和漏洞的威脅 1.5.2 惡意軟件1.5.2.1 惡意軟件的定義1.5.2.2 惡意軟件的威脅 1.…

攜手AI,如何共贏未來?

5/25日參加了一個培訓分享會&#xff0c;由博奧研究院、武漢博奕咨詢和華工科技聯合舉辦&#xff0c;主題是“攜手Ai&#xff0c;共贏未來”。 抱著跟書友線下交流的心態我參與了&#xff0c;參與前我對博奧做了基礎了解&#xff0c;他們跟工信部考試和教育中心有合作&#x…