<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          進(jìn)程是如何使用內(nèi)存的?

          共 3275字,需瀏覽 7分鐘

           ·

          2021-05-15 23:55


          程序運(yùn)行概述

          程序(我們這里只討論單進(jìn)程情況,存在多進(jìn)程的程序如淘寶微信等不展開(kāi)討論)鏡像存在磁盤(pán)中,運(yùn)行時(shí)將鏡像加載至內(nèi)存RAM中,然后開(kāi)始執(zhí)行。


          先來(lái)看一下CPU的多級(jí)存儲(chǔ)結(jié)構(gòu),CPU通用寄存器訪問(wèn)速度最快,其次是Cache,再次是內(nèi)存,磁盤(pán)訪問(wèn)速度最慢。

          CPU的多級(jí)存儲(chǔ)結(jié)構(gòu)


          對(duì)于進(jìn)程而言,可使用的地址空間為2^32=4G,那么對(duì)于只有2G內(nèi)存甚至只有256M內(nèi)存的嵌入式設(shè)備怎么辦?這個(gè)時(shí)候就需要MMU負(fù)責(zé)將進(jìn)程的虛擬地址轉(zhuǎn)換為內(nèi)存的真實(shí)物理地址。如何管理這種映射關(guān)系呢??jī)?nèi)核中為每個(gè)進(jìn)程分配了進(jìn)程頁(yè)表。對(duì)應(yīng)下圖可以看到,只有正在使用的虛擬地址空間才會(huì)真正分配到物理頁(yè)框;同時(shí)對(duì)于內(nèi)核空間地址映射對(duì)于不同進(jìn)程物理地址一樣。

                                                           進(jìn)程地址映射

          TLB工作原理

          上圖中不同進(jìn)程映射到物理內(nèi)存使用到了TLB表(地址變換高速緩存),流程為:CPU獲取數(shù)據(jù)或指令:獲取進(jìn)程頁(yè)表,拿到物理地址;訪問(wèn)內(nèi)存物理地址拿到真實(shí)數(shù)據(jù)。

          每次執(zhí)行指令,先從TLB表中獲取,如果未命中,則從內(nèi)存中獲取,同時(shí)根據(jù)LRU方法更新TLB表。這里提一下,LRU更新方法在很多地方都用得到,像CDN頁(yè)面緩存、CPU cache緩存等,如何消除cache顛簸的影響,是另一個(gè)話題。

          局部性原理:時(shí)間及空間局部性,即CPU訪問(wèn)某個(gè)邏輯地址的數(shù)據(jù)時(shí),大概率會(huì)繼續(xù)訪問(wèn)該虛擬地址相鄰的地址。因此為了保證cache的命中率,一般CPU采用多級(jí)流水線設(shè)計(jì),將預(yù)取指令及相鄰的地址空間存放至TLB表中。


          每個(gè)核都有自己的TLB,由MMU內(nèi)存管理單元模塊執(zhí)行,流程為:CPU發(fā)送執(zhí)行進(jìn)程的虛擬地址給MMU模塊,MMU對(duì)應(yīng)的硬件電路獲取TLB表物理地址并訪問(wèn)數(shù)據(jù)。

          如果進(jìn)程使用了4G虛擬地址,那么所需要的頁(yè)表項(xiàng)條目為:

          4G/4K=1M


          每個(gè)頁(yè)表項(xiàng)為4Byte,因此進(jìn)程頁(yè)表占據(jù)了4M物理內(nèi)存空間。這種狀態(tài)下可以使用多級(jí)頁(yè)表減少內(nèi)存占用,且可以離散存儲(chǔ)。

           

          ====

          從malloc說(shuō)起

          使用malloc分配16k空間,這16k不會(huì)立即占用16k真實(shí)內(nèi)存,而是采用寫(xiě)時(shí)復(fù)制的方式使用。如果物理內(nèi)存已經(jīng)寫(xiě)滿數(shù)據(jù)怎么辦(可能被多個(gè)進(jìn)程占用)?這個(gè)時(shí)候就繼續(xù)使用上面提到的LRU方式進(jìn)行頁(yè)表置換。置換過(guò)程中會(huì)將換出的頁(yè)表真實(shí)寫(xiě)入磁盤(pán)中,一般由daemon守護(hù)進(jìn)程完成。


          前面使用malloc分配空間之后,linux內(nèi)核并未真正給該進(jìn)程分配物理頁(yè),如果對(duì)該地址進(jìn)行寫(xiě)動(dòng)作,會(huì)由MMU觸發(fā)缺頁(yè)中斷,這時(shí)進(jìn)入內(nèi)核終端處理程序,將數(shù)據(jù)從磁盤(pán)加載至內(nèi)存。

           

                                                              CPU尋址流程


          下面總結(jié)一下CPU尋址流程:CPU將進(jìn)程虛擬地址通過(guò)地址總線發(fā)送給MMU,由MMU硬件電路轉(zhuǎn)換成物理地址,然后通過(guò)數(shù)據(jù)總線訪問(wèn)內(nèi)存獲取數(shù)據(jù)。

          CPU獲取物理地址流程如下:


          1、CPU發(fā)送虛擬地址,MMU查詢(xún)自身TLB表,如果命中:根據(jù)物理地址訪問(wèn)數(shù)據(jù)頁(yè);如果不命中,通過(guò)cr3寄存器取出進(jìn)程頁(yè)表物理地址訪問(wèn)進(jìn)程頁(yè)表。

          2、這里訪問(wèn)進(jìn)程頁(yè)表先是從Cache中獲取緩存頁(yè)框,如果Cache命中:從Cache中獲取得到物理地址,更新TLB表。如果不命中,直接訪問(wèn)內(nèi)存頁(yè)表。

          3、進(jìn)程頁(yè)表保存了進(jìn)程使用過(guò)程中所有的虛擬地址對(duì)應(yīng)的表項(xiàng),因此通過(guò)頁(yè)表地址偏移可直接獲取到頁(yè)表項(xiàng),并更新至Cache中。

          4、繼續(xù)第一步,MMU從Cache中獲取頁(yè)表項(xiàng),并查看虛擬地址是否已分配物理頁(yè)框。若分配,則使用LRU算法更新TLB表并通過(guò)內(nèi)存物理地址訪問(wèn)數(shù)據(jù);若沒(méi)分配物理頁(yè)框,則觸發(fā)Page Fault缺頁(yè)中斷,進(jìn)入并執(zhí)行中斷接管程序。

          5、中斷處理程序?yàn)榘l(fā)送的虛擬地址分配真實(shí)物理頁(yè)框,如果內(nèi)存數(shù)據(jù)已滿,根據(jù)LRU算法淘汰最久未用的頁(yè)面,置換磁盤(pán)的進(jìn)程映像至物理頁(yè)框,并更新進(jìn)程頁(yè)表。(用戶空間的缺頁(yè)中斷還會(huì)判斷是否非法訪問(wèn)等權(quán)限校驗(yàn),這里不展開(kāi))

          6、中斷處理程序返回,CPU獲取執(zhí)行權(quán),繼續(xù)執(zhí)行指令。

          獲取到了物理地址,根據(jù)物理地址獲取實(shí)際數(shù)據(jù)流程為:MMU通過(guò)物理地址查詢(xún)Cache,如果緩存命中,CPU直接獲取Cache中數(shù)據(jù)并繼續(xù)執(zhí)行;如果不命中,那么根據(jù)物理地址獲取內(nèi)存中的數(shù)據(jù),硬件電路將物理頁(yè)框存入Cache中,CPU從Cache中獲取數(shù)據(jù)。

           


          CPU獲取數(shù)據(jù)流程


          理想狀態(tài)下,當(dāng)進(jìn)程局部性較高時(shí),如執(zhí)行while循環(huán),MMU獲取TLB表命中拿到物理地址,通過(guò)物理地址訪問(wèn)Cache命中拿到真實(shí)數(shù)據(jù)。

           

          具體示例代碼分析代碼數(shù)據(jù)流及執(zhí)行流

          char* ptr =malloc(1*1024*1024);  //1、分配內(nèi)存memcpy(ptr, 'a',10);     //2、寫(xiě)入數(shù)據(jù)ptr[100] = 'b';    //3、賦值


          第一行:char* ptr =malloc(1*1024*1024);

          假定malloc分配的虛擬地址是0x00000040,表示【0x00000040-0x00100040】這1M進(jìn)程虛擬空間被分配成功。接下來(lái)我們看一下進(jìn)程頁(yè)表情況。

          0x00000040  ->  64

          0x00100040  ->  1048640


          也就是這段虛擬空間占了1048576塊頁(yè)表項(xiàng)。這里注意,如果是一級(jí)頁(yè)表,不管有沒(méi)有執(zhí)行malloc,這些頁(yè)表項(xiàng)都存在,但如果是多級(jí)頁(yè)表,只有真實(shí)訪問(wèn)數(shù)據(jù)的時(shí)候這些頁(yè)表才會(huì)占用物理內(nèi)存空間。接下來(lái)計(jì)算頁(yè)號(hào)和頁(yè)內(nèi)偏移:

          起始地址虛擬頁(yè)號(hào):64/(4*1024)= 0,頁(yè)內(nèi)偏移為64%(4*1024)= 0x40;

          結(jié)束地址虛擬頁(yè)號(hào):1048640/(4*1024)= 256,頁(yè)內(nèi)偏移為1048640%(4*1024)= 0x40;


          第二行:memcpy (ptr,'g', 10);

          根據(jù)ptr虛擬地址找到頁(yè)表項(xiàng),發(fā)現(xiàn)并沒(méi)有分配物理頁(yè)框,觸發(fā)缺頁(yè)中斷后分配得到第100頁(yè)框。然后CPU將ptr對(duì)應(yīng)虛擬地址往后的10字節(jié)空間寫(xiě)為‘a(chǎn)’。這里說(shuō)一下,雖然進(jìn)程頁(yè)號(hào)對(duì)應(yīng)的物理頁(yè)框序號(hào)不一定相同,因?yàn)轫?yè)框大小為4k,所以虛擬地址在進(jìn)程頁(yè)號(hào)中的偏移等于映射的物理地址在物理頁(yè)框中的偏移


          CPU根據(jù)虛擬地址按照上一章的流程找到對(duì)應(yīng)物理地址,將第100物理頁(yè)框加載至Cache中,CPU將10字節(jié)’a’寫(xiě)入Cache。


          第三行:ptr[100] = 'b';


          根據(jù)局部性原理,這里訪問(wèn)的就是同一個(gè)虛擬地址附近的數(shù)據(jù),因此TLB和Cache都命中。

          可以看到,進(jìn)程在執(zhí)行malloc時(shí)是將物理頁(yè)框直接分配給虛擬地址,里面的初始數(shù)據(jù)有內(nèi)存的電氣特性決定,是隨機(jī)值,因此maoolc出來(lái)的空間使用前需要賦值或者執(zhí)行初始化操作。




          推薦閱讀:
          專(zhuān)輯|Linux文章匯總
          專(zhuān)輯|程序人生
          專(zhuān)輯|C語(yǔ)言
          我的知識(shí)小密圈

          關(guān)注公眾號(hào),后臺(tái)回復(fù)「1024」獲取學(xué)習(xí)資料網(wǎng)盤(pán)鏈接。

          歡迎點(diǎn)贊,關(guān)注,轉(zhuǎn)發(fā),在看,您的每一次鼓勵(lì),我都將銘記于心~



          瀏覽 30
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产成人 亚洲 欧洲在线 | 视频在线99 | 午夜成人社区 | 爱爱91| 国产无码天美 |