欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
linux環(huán)境內存分配原理

Linux的虛擬內存管理有幾個(gè)關(guān)鍵概念

Linux 虛擬地址空間如何分布?malloc和free是如何分配和釋放內存?如何查看堆內內存的碎片情況?既然堆內內存brk和sbrk不能直接釋放,為什么不全部使用 mmap 來(lái)分配,munmap直接釋放呢 ?


Linux 的虛擬內存管理有幾個(gè)關(guān)鍵概念:
1、每個(gè)進(jìn)程都有獨立的虛擬地址空間,進(jìn)程訪(fǎng)問(wèn)的虛擬地址并不是真正的物理地址;
2、虛擬地址可通過(guò)每個(gè)進(jìn)程上的頁(yè)表(在每個(gè)進(jìn)程的內核虛擬地址空間)與物理地址進(jìn)行映射,獲得真正物理地址;
3、如果虛擬地址對應物理地址不在物理內存中,則產(chǎn)生缺頁(yè)中斷,真正分配物理地址,同時(shí)更新進(jìn)程的頁(yè)表;如果此時(shí)物理內存已耗盡,則根據內存替換算法淘汰部分頁(yè)面至物理磁盤(pán)中。
  

一、Linux 虛擬地址空間如何分布?
Linux 使用虛擬地址空間,大大增加了進(jìn)程的尋址空間,由低地址到高地址分別為
1、只讀段:該部分空間只能讀,不可寫(xiě);(包括:代碼段、rodata 段(C常量字符串和#define定義的常量) )
2、數據段:保存全局變量、靜態(tài)變量的空間;
3、堆 :就是平時(shí)所說(shuō)的動(dòng)態(tài)內存, malloc/new 大部分都來(lái)源于此。其中堆頂的位置可通過(guò)函數 brk 和 sbrk 進(jìn)行動(dòng)態(tài)調整。
4、文件映射區域 :動(dòng)態(tài)庫、共享內存等映射物理空間的內存,一般是 mmap 函數所分配的虛擬地址空間。
5、棧:用于維護函數調用的上下文空間,一般為 8M ,可通過(guò) ulimit –s 查看。
6、內核虛擬空間:用戶(hù)代碼不可見(jiàn)的內存區域,由內核管理(頁(yè)表就存放在內核虛擬空間)。
下圖是 32 位系統典型的虛擬地址空間分布(來(lái)自《深入理解計算機系統》)。

32 位系統有4G 的地址空間::

      其中 0x08048000~0xbfffffff 是用戶(hù)空間,0xc0000000~0xffffffff 是內核空間,包括內核代碼和數據、與進(jìn)程相關(guān)的數據結構(如頁(yè)表、內核棧)等。另外,%esp 執行棧頂,往低地址方向變化;brk/sbrk 函數控制堆頂_edata往高地址方向變化。


64位系統結果怎樣呢? 64 位系統是否擁有 2^64 的地址空間嗎?
事實(shí)上, 64 位系統的虛擬地址空間劃分發(fā)生了改變:
1、地址空間大小不是2^32,也不是2^64,而一般是2^48。

因為并不需要 2^64 這么大的尋址空間,過(guò)大空間只會(huì )導致資源的浪費。64位Linux一般使用48位來(lái)表示虛擬地址空間,40位表示物理地址,
這可通過(guò)#cat  /proc/cpuinfo 來(lái)查看:


2、其中,0x0000000000000000~0x00007fffffffffff 表示用戶(hù)空間, 0xFFFF800000000000~ 0xFFFFFFFFFFFFFFFF 表示內核空間,共提供 256TB(2^48) 的尋址空間。
這兩個(gè)區間的特點(diǎn)是,第 47 位與 48~63 位相同,若這些位為 0 表示用戶(hù)空間,否則表示內核空間。
3、用戶(hù)空間由低地址到高地址仍然是只讀段、數據段、堆、文件映射區域和棧;


二、malloc和free是如何分配和釋放內存?

如何查看進(jìn)程發(fā)生缺頁(yè)中斷的次數?

         用# ps -o majflt,minflt -C program 命令查看


          majflt代表major fault,中文名叫大錯誤,minflt代表minor fault,中文名叫小錯誤。

          這兩個(gè)數值表示一個(gè)進(jìn)程自啟動(dòng)以來(lái)所發(fā)生的缺頁(yè)中斷的次數。

可以用命令ps -o majflt minflt -C program來(lái)查看進(jìn)程的majflt, minflt的值,這兩個(gè)值都是累加值,從進(jìn)程啟動(dòng)開(kāi)始累加。在對高性能要求的程序做壓力測試的時(shí)候,我們可以多關(guān)注一下這兩個(gè)值。 
如果一個(gè)進(jìn)程使用了mmap將很大的數據文件映射到進(jìn)程的虛擬地址空間,我們需要重點(diǎn)關(guān)注majflt的值,因為相比minflt,majflt對于性能的損害是致命的,隨機讀一次磁盤(pán)的耗時(shí)數量級在幾個(gè)毫秒,而minflt只有在大量的時(shí)候才會(huì )對性能產(chǎn)生影響。

發(fā)成缺頁(yè)中斷后,執行了那些操作?

當一個(gè)進(jìn)程發(fā)生缺頁(yè)中斷的時(shí)候,進(jìn)程會(huì )陷入內核態(tài),執行以下操作
1、檢查要訪(fǎng)問(wèn)的虛擬地址是否合法
2、查找/分配一個(gè)物理頁(yè)
3、填充物理頁(yè)內容(讀取磁盤(pán),或者直接置0,或者啥也不干)
4、
建立映射關(guān)系(虛擬地址到物理地址)
重新執行發(fā)生缺頁(yè)中斷的那條指令
如果第3步,需要讀取磁盤(pán),那么這次缺頁(yè)中斷就是majflt,否則就是minflt。

內存分配的原理

從操作系統角度來(lái)看,進(jìn)程分配內存有兩種方式,分別由兩個(gè)系統調用完成:brk和mmap(不考慮共享內存)。

1、brk是將數據段(.data)的最高地址指針_edata往高地址推;

2、mmap是在進(jìn)程的虛擬地址空間中(堆和棧中間,稱(chēng)為文件映射區域的地方)找一塊空閑的虛擬內存。

     這兩種方式分配的都是虛擬內存,沒(méi)有分配物理內存。在第一次訪(fǎng)問(wèn)已分配的虛擬地址空間的時(shí)候,發(fā)生缺頁(yè)中斷,操作系統負責分配物理內存,然后建立虛擬內存和物理內存之間的映射關(guān)系。


在標準C庫中,提供了malloc/free函數分配釋放內存,這兩個(gè)函數底層是由brk,mmap,munmap這些系統調用實(shí)現的。


下面以一個(gè)例子來(lái)說(shuō)明內存分配的原理:

情況一、malloc小于128k的內存,使用brk分配內存,將_edata往高地址推(只分配虛擬空間,不對應物理內存(因此沒(méi)有初始化),第一次讀/寫(xiě)數據時(shí),引起內核缺頁(yè)中斷,內核才分配對應的物理內存,然后虛擬地址空間建立映射關(guān)系),如下圖:

1、進(jìn)程啟動(dòng)的時(shí)候,其(虛擬)內存空間的初始布局如圖1所示。
      其中,mmap內存映射文件是在堆和棧的中間(例如libc-2.2.93.so,其它數據文件等),為了簡(jiǎn)單起見(jiàn),省略了內存映射文件。
      _edata指針(glibc里面定義)指向數據段的最高地址。
2、
進(jìn)程調用A=malloc(30K)以后,內存空間如圖2:
      malloc函數會(huì )調用brk系統調用,將_edata指針往高地址推30K,就完成虛擬內存分配。
      你可能會(huì )問(wèn):只要把_edata+30K就完成內存分配了?
      事實(shí)是這樣的,_edata+30K只是完成虛擬地址的分配,A這塊內存現在還是沒(méi)有物理頁(yè)與之對應的,等到進(jìn)程第一次讀寫(xiě)A這塊內存的時(shí)候,發(fā)生缺頁(yè)中斷,這個(gè)時(shí)候,內核才分配A這塊內存對應的物理頁(yè)。也就是說(shuō),如果用malloc分配了A這塊內容,然后從來(lái)不訪(fǎng)問(wèn)它,那么,A對應的物理頁(yè)是不會(huì )被分配的。
3、
進(jìn)程調用B=malloc(40K)以后,內存空間如圖3。

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

4、進(jìn)程調用C=malloc(200K)以后,內存空間如圖4:
      默認情況下,malloc函數分配內存,如果請求內存大于128K(可由M_MMAP_THRESHOLD選項調節),那就不是去推_edata指針了,而是利用mmap系統調用,從堆和棧的中間分配一塊虛擬內存。
      這樣子做主要是因為::
      brk分配的內存需要等到高地址內存釋放以后才能釋放(例如,在B釋放之前,A是不可能釋放的,這就是內存碎片產(chǎn)生的原因,什么時(shí)候緊縮看下面),而mmap分配的內存可以單獨釋放。
      當然,還有其它的好處,也有壞處,再具體下去,有興趣的同學(xué)可以去看glibc里面malloc的代碼了。
5、進(jìn)程調用D=malloc(100K)以后,內存空間如圖5;
6、進(jìn)程調用free(C)以后,C對應的虛擬內存和物理內存一起釋放。

7、進(jìn)程調用free(B)以后,如圖7所示:
        B對應的虛擬內存和物理內存都沒(méi)有釋放,因為只有一個(gè)_edata指針,如果往回推,那么D這塊內存怎么辦呢?
當然,B這塊內存,是可以重用的,如果這個(gè)時(shí)候再來(lái)一個(gè)40K的請求,那么malloc很可能就把B這塊內存返回回去了。
8、進(jìn)程調用free(D)以后,如圖8所示:
        B和D連接起來(lái),變成一塊140K的空閑內存。
9、默認情況下:
       當最高地址空間的空閑內存超過(guò)128K(可由M_TRIM_THRESHOLD選項調節)時(shí),執行內存緊縮操作(trim)。在上一個(gè)步驟free的時(shí)候,發(fā)現最高地址空閑內存超過(guò)128K,于是內存緊縮,變成圖9所示。

真相大白
說(shuō)完內存分配的原理,那么被測模塊在內核態(tài)cpu消耗高的原因就很清楚了:每次請求來(lái)都malloc一塊2M的內存,默認情況下,malloc調用mmap分配內存,請求結束的時(shí)候,調用munmap釋放內存。假設每個(gè)請求需要6個(gè)物理頁(yè),那么每個(gè)請求就會(huì )產(chǎn)生6個(gè)缺頁(yè)中斷,在2000的壓力下,每秒就產(chǎn)生了10000多次缺頁(yè)中斷,這些缺頁(yè)中斷不需要讀取磁盤(pán)解決,所以叫做minflt;缺頁(yè)中斷在內核態(tài)執行,因此進(jìn)程的內核態(tài)cpu消耗很大。缺頁(yè)中斷分散在整個(gè)請求的處理過(guò)程中,所以表現為分配語(yǔ)句耗時(shí)(10us)相對于整條請求的處理時(shí)間(1000us)比重很小。

解決辦法
將動(dòng)態(tài)內存改為靜態(tài)分配,或者啟動(dòng)的時(shí)候,用malloc為每個(gè)線(xiàn)程分配,然后保存在threaddata里面。但是,由于這個(gè)模塊的特殊性,靜態(tài)分配,或者啟動(dòng)時(shí)候分配都不可行。另外,Linux下默認棧的大小限制是10M,如果在棧上分配幾M的內存,有風(fēng)險。 
禁止malloc調用mmap分配內存,禁止內存緊縮。
在進(jìn)程啟動(dòng)時(shí)候,加入以下兩行代碼:
mallopt(M_MMAP_MAX, 0); // 禁止malloc調用mmap分配內存
mallopt(M_TRIM_THRESHOLD, -1); // 禁止內存緊縮
效果:加入這兩行代碼以后,用ps命令觀(guān)察,壓力穩定以后,majlt和minflt都為0。進(jìn)程的系統態(tài)cpu從20降到10。


三、如何查看堆內內存的碎片情況 ?

glibc 提供了以下結構和接口來(lái)查看堆內內存和 mmap 的使用情況。
struct mallinfo {
  int arena;            /* non-mmapped space allocated from system */
  int ordblks;         /* number of free chunks */
  int smblks;          /* number of fastbin blocks */
  int hblks;             /* number of mmapped regions */
  int hblkhd;           /* space in mmapped regions */
  int usmblks;        /* maximum total allocated space */
  int fsmblks;         /* space available in freed fastbin blocks */
  int uordblks;        /* total allocated space */
  int fordblks;         /* total free space */
  int keepcost;       /* top-most, releasable (via malloc_trim) space */
};

/*返回heap(main_arena)的內存使用情況,以 mallinfo 結構返回 */
struct mallinfo mallinfo();

/* 將heap和mmap的使用情況輸出到stderr*/
void malloc_stats();

可通過(guò)以下例子來(lái)驗證mallinfo和malloc_stats輸出結果。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <malloc.h>

size_t  heap_malloc_total, heap_free_total,mmap_total, mmap_count;

void print_info()
{
    struct mallinfo mi = mallinfo();
 
    printf("count by itself:\n");
    printf("\theap_malloc_total=%lu heap_free_total=%lu heap_in_use=%lu\n\tmmap_total=%lu mmap_count=%lu\n",
              heap_malloc_total*1024, heap_free_total*1024, heap_malloc_total*1024-heap_free_total*1024,
              mmap_total*1024, mmap_count);
 
 printf("count by mallinfo:\n");
 printf("\theap_malloc_total=%lu heap_free_total=%lu heap_in_use=%lu\n\tmmap_total=%lu mmap_count=%lu\n",
             mi.arena, mi.fordblks, mi.uordblks,
             mi.hblkhd, mi.hblks);
 
 printf("from malloc_stats:\n");
 malloc_stats();
}

#define ARRAY_SIZE 200
int main(int argc, char** argv)
{
    char** ptr_arr[ARRAY_SIZE];
    int i; 
    for( i = 0; i < ARRAY_SIZE; i++)
    {
            ptr_arr[i] = malloc(i * 1024); 
            if ( i < 128)                                      //glibc默認128k以上使用mmap
            {
                    heap_malloc_total += i;
            }
            else
            {
                    mmap_total += i;
                   mmap_count++;
            }
    } 
    print_info(); 


    for( i = 0; i < ARRAY_SIZE; i++)
    {
           if ( i % 2 == 0)
                continue;
           free(ptr_arr[i]);

           if ( i < 128)
           {
                   heap_free_total += i;
           }
           else
           {
                  mmap_total -= i;
                  mmap_count--;
           }
    } 
    
    printf("\nafter free\n");
    print_info(); 


    return 1;
}

該例子第一個(gè)循環(huán)為指針數組每個(gè)成員分配索引位置 (KB) 大小的內存塊,并通過(guò) 128 為分界分別對 heap 和 mmap 內存分配情況進(jìn)行計數;
第二個(gè)循環(huán)是 free 索引下標為奇數的項,同時(shí)更新計數情況。通過(guò)程序的計數與mallinfo/malloc_stats 接口得到結果進(jìn)行對比,并通過(guò) print_info打印到終端。

 
下面是一個(gè)執行結果:
count by itself:
        heap_malloc_total=8323072 heap_free_total=0 heap_in_use=8323072
        mmap_total=12054528 mmap_count=72
  
count by mallinfo:
        heap_malloc_total=8327168 heap_free_total=2032 heap_in_use=8325136
        mmap_total=12238848 mmap_count=72

from malloc_stats:
Arena 0:
system bytes     =    8327168
in use bytes     =    8325136
Total (incl. mmap):
system bytes     =   20566016
in use bytes     =   20563984
max mmap regions =         72
max mmap bytes   =   12238848

after free
count by itself:
        heap_malloc_total=8323072 heap_free_total=4194304 heap_in_use=4128768
        mmap_total=6008832 mmap_count=36

count by mallinfo:
        heap_malloc_total=8327168 heap_free_total=4197360 heap_in_use=4129808
        mmap_total=6119424 mmap_count=36

from malloc_stats:
Arena 0:
system bytes     =    8327168
in use bytes     =    4129808
Total (incl. mmap):
system bytes     =   14446592
in use bytes     =   10249232
max mmap regions =         72
max mmap bytes   =   12238848

由上可知,程序統計和mallinfo 得到的信息基本吻合,其中 heap_free_total 表示堆內已釋放的內存碎片總和。 
 
       如果想知道堆內究竟有多少碎片,可通過(guò) mallinfo 結構中的 fsmblks 、smblks 、ordblks 值得到,這些值表示不同大小區間的碎片總個(gè)數,這些區間分別是 0~80 字節,80~512 字節,512~128k。如果 fsmblks 、 smblks 的值過(guò)大,那碎片問(wèn)題可能比較嚴重了。
    不過(guò), mallinfo 結構有一個(gè)很致命的問(wèn)題,就是其成員定義全部都是 int ,在 64 位環(huán)境中,其結構中的 uordblks/fordblks/arena/usmblks 很容易就會(huì )導致溢出,應該是歷史遺留問(wèn)題,使用時(shí)要注意!

 

四、既然堆內內存brk和sbrk不能直接釋放,為什么不全部使用 mmap 來(lái)分配,munmap直接釋放呢? 
        既然堆內碎片不能直接釋放,導致疑似“內存泄露”問(wèn)題,為什么 malloc 不全部使用 mmap 來(lái)實(shí)現呢(mmap分配的內存可以會(huì )通過(guò) munmap 進(jìn)行 free ,實(shí)現真正釋放)?而是僅僅對于大于 128k 的大塊內存才使用 mmap ? 

        其實(shí),進(jìn)程向 OS 申請和釋放地址空間的接口 sbrk/mmap/munmap 都是系統調用,頻繁調用系統調用都比較消耗系統資源的。并且, mmap 申請的內存被 munmap 后,重新申請會(huì )產(chǎn)生更多的缺頁(yè)中斷。例如使用 mmap 分配 1M 空間,第一次調用產(chǎn)生了大量缺頁(yè)中斷 (1M/4K 次 ) ,當munmap 后再次分配 1M 空間,會(huì )再次產(chǎn)生大量缺頁(yè)中斷。缺頁(yè)中斷是內核行為,會(huì )導致內核態(tài)CPU消耗較大。另外,如果使用 mmap 分配小內存,會(huì )導致地址空間的分片更多,內核的管理負擔更大。
        同時(shí)堆是一個(gè)連續空間,并且堆內碎片由于沒(méi)有歸還 OS ,如果可重用碎片,再次訪(fǎng)問(wèn)該內存很可能不需產(chǎn)生任何系統調用和缺頁(yè)中斷,這將大大降低 CPU 的消耗。 因此, glibc 的 malloc 實(shí)現中,充分考慮了 sbrk 和 mmap 行為上的差異及優(yōu)缺點(diǎn),默認分配大塊內存 (128k) 才使用 mmap 獲得地址空間,也可通過(guò) mallopt(M_MMAP_THRESHOLD, <SIZE>) 來(lái)修改這個(gè)臨界值。

 

五、如何查看進(jìn)程的缺頁(yè)中斷信息?
可通過(guò)以下命令查看缺頁(yè)中斷信息
ps -o majflt,minflt -C <program_name>
ps -o majflt,minflt -p <pid>
其中:: majflt 代表 major fault ,指大錯誤;

           minflt 代表 minor fault ,指小錯誤。

這兩個(gè)數值表示一個(gè)進(jìn)程自啟動(dòng)以來(lái)所發(fā)生的缺頁(yè)中斷的次數。
其中 majflt 與 minflt 的不同是::

        majflt 表示需要讀寫(xiě)磁盤(pán),可能是內存對應頁(yè)面在磁盤(pán)中需要load 到物理內存中,也可能是此時(shí)物理內存不足,需要淘汰部分物理頁(yè)面至磁盤(pán)中。

參看:: http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201210975312473/

 

六、除了 glibc 的 malloc/free ,還有其他第三方實(shí)現嗎?

        其實(shí),很多人開(kāi)始詬病 glibc 內存管理的實(shí)現,特別是高并發(fā)性能低下和內存碎片化問(wèn)題都比較嚴重,因此,陸續出現一些第三方工具來(lái)替換 glibc 的實(shí)現,最著(zhù)名的當屬 google 的tcmalloc和facebook 的jemalloc 。
        網(wǎng)上有很多資源,可以自己查(只用使用第三方庫,代碼不用修改,就可以使用第三方庫中的malloc)。

 

參考資料:
《深入理解計算機系統》第 10 章
http://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt

https://www.ibm.com/developerworks/cn/linux/l-lvm64/

http://www.kerneltravel.net/journal/v/mem.htm

http://blog.csdn.net/baiduforum/article/details/6126337

http://www.nosqlnotes.net/archives/105


原文地址:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201210975312473/


本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Linux操作系統的內存使用方法詳細解析 .
談?wù)刴alloc
[百度分享]頻繁分配釋放內存導致的性能問(wèn)題的分析
linux 是如何進(jìn)行內存分配的
adb shell dumpsys meminfo 詳解
malloc 從哪里得到的內存空間
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久