對程序內存結構和程序存儲位置的理解

對程序內存結構和程序存儲位置的理解

以前看過許多有關係統中,對內存分配的一些文章,一直只知其一;不知其二,直到調研一個系統調用,才真正的弄明白是怎麼回事. 有一個重點就是,這裏說的全局數據區,全局,說的不說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 查看系統的頁大小

相關文章
相關標籤/搜索