以前看過許多有關係統中,對內存分配的一些文章,一直只知其一;不知其二,直到調研一個系統調用,才真正的弄明白是怎麼回事. 有一個重點就是,這裏說的全局數據區,全局,說的不說c++中的全局的概念,若是那樣理解很容易感受模棱兩可,這裏說的全局說 系統看來,不是一個程序的看待,對系統來講,一個程序的全局就是,須要在程序運行前準備好的內存,對於c++中的變量,系統看來只有三種:全局,stack,bss, 其餘兩個,stack管程序調用,bss指須要,可是運行的時候才能知道內容. 加載慢的一個優化手段就是,調整程序,讓bss代替data,具體爲何,下文會說,linux
這個內容想寫寫來源於對一個系統調用的研究 brk(void* addr), 某些程序加載的時候cpu很高,使用strace -p PID查看之後,發現他 一直執行brk這個系統調用.ios
brk: 調整程序的數據段,把數據段的地址往高地址調整,,,,,這個有啥用?地址段不是應該加載的時候分配好的嗎?有的說這個還能分配動態內存,動態內存不是在heep區分配的嗎?總之疑點重重.c++
通常系統中的地址分配都是從低到高, 依次是:函數
text段 => 存放指令代碼,在可執行文件中也由這一部分,系統會把文件中的text端拷貝到內存裏優化
bss段 => 未初始化的全局數據區,通常系統會弄成0,這一部分在可執行文件中是沒有的,只是記錄一下須要多少這種空間spa
data數據段 => 這一部分比較特殊,下文會具體說明,可執行文件中可能有也可能沒有.指針
——-> 這有個指針(系統用的,不過用戶態能夠經過調用修改) _edata內存
heep堆 => 這是一般 認爲 的malloc申請內存的地方,其實也不必定的,下文會說get
stack棧地址 => 棧地址,一般的函數調式都會用到的,io
==>
==>
3G以上就是內核區了,用戶態就別想自由使用了.
brk的功能就是,把 _edata的地址網高出推,往 heap這邊推,能夠想象,brk把_data往heep推了,heep能分配的空間確定就少了啊,
對的,是這樣的,
有關brk分配內存的說明
c語言中分配內存,固然是使用malloc了,brk分配內存的功能,就是在這裏的,glibc對malloc的實現,是若是分配的內存在 126k之內, 就使用brk分配,把brk往heep端推一點,多餘出來的數據段,返回給用戶,用做動態內存,當讀寫這個內存的時候,就會引起一個 缺頁中斷 讓系統在物理內存裏分配段內存. 126k之內都用brk,咱們平時試試的基本都是使用brk分配的啊,我不信!!,我寫個程序給你證實
#include<iostream> #include<unistd.h> #include<stdlib.h> using namespace std; int main(){ void*p = malloc(1); cout<<p<<endl; int a = brk((void*)((char*)p+1000)); //這句調步調影響下次malloc返回的地址 //int a = brk((void*)((char*)p+1)); cout<<a<<endl; void* d=malloc(1); cout<<d<<endl; return 0; }
一開始我使用 brk(p+1) 程序直接崩潰了,後來查了一下兩次malloc的地址差,發現一次malloc 已經把_edata的地址上調了460了,若是我在上調,只能調這個數更大的範圍了, 這裏有個隱含規則 brk 的地址,只能往高處調,不能往低處調,由於已經調好的內存, 可能已經分配了,咱們私自把地址往下調了,brk也返回成功0,但是程序會直接崩潰.
若是malloc申請的地址超過了126k,纔會調用mmap到heap區去申請內存. brk和heap是linux系統調用,malloc是glibc的函數,不是系統調用.
若是_edata只能往上調,那麼,即便malloc把內存釋放了,把_edata調下來,也只能依次釋放的,但是用戶程序不必定這樣來,這不就是 浪費嗎? 是的,是這樣,用戶free,這個地址的一段內存就不能回收了,只有當最高處的地址被free了, 才能把_edata調下來,同時通知系統,取消映射. malloc默認沒有一個一個字節的向高地址加,而是一次就加許多,這個許多如何知道呢,這個和系統分配的頁大小有關,查看辦法以下: 使用getconf PAGESIZE 查看系統的頁大小