新聞中心

        EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > linux下內(nèi)存管理學(xué)習(xí)心得(二)

        linux下內(nèi)存管理學(xué)習(xí)心得(二)

        作者: 時(shí)間:2016-11-23 來源:網(wǎng)絡(luò) 收藏
        接著上面的知識(shí),這篇主要總結(jié)如下幾個(gè)方面知識(shí):

        1、物理地址的頁(yè)、區(qū)等概念

        本文引用地址:http://www.104case.com/article/201611/320402.htm

        2、內(nèi)核使用內(nèi)存的函數(shù)

        3、分配字節(jié)與分配頁(yè)

        一、區(qū)、頁(yè)

        前面linux下內(nèi)存管理學(xué)習(xí)心得(一)也已經(jīng)說了關(guān)于頁(yè)的概念,在內(nèi)核下面是把物理頁(yè)(頁(yè)框)作為分配的基本單元,內(nèi)核下使用struct page結(jié)構(gòu)體來表示系統(tǒng)中的物理頁(yè)其中該結(jié)構(gòu)體表示頁(yè)是否被鎖定在內(nèi)存中,是否為臟頁(yè),該頁(yè)被引用幾次,同時(shí)還有頁(yè)的虛擬地址等等。關(guān)鍵一點(diǎn)page結(jié)構(gòu)只與物理頁(yè)有關(guān)而與虛擬頁(yè)無(wú)關(guān),結(jié)構(gòu)僅僅目的在于描述物理內(nèi)存本身,而不是描述包含在其中物理頁(yè)中的數(shù)據(jù)。

        下面說明一下如何尋址到物理頁(yè):

        機(jī)器語(yǔ)言指令中出現(xiàn)的內(nèi)存地址,都是邏輯地址,需要轉(zhuǎn)換成線性地址,再經(jīng)過MMU(CPU中的內(nèi)存管理單元)轉(zhuǎn)換成物理地址才能夠被訪問到。

        我們寫個(gè)最簡(jiǎn)單的hello world程序,用gccs編譯,再反編譯后會(huì)看到以下指令:

        mov 0x80495b0, %eax

        這里的內(nèi)存地址0x80495b0就是一個(gè)邏輯地址,必須加上隱含的DS數(shù)據(jù)段的基地址,才能構(gòu)成線性地址。也就是說0x80495b0是當(dāng)前任務(wù)的DS數(shù)據(jù)段內(nèi)的偏移。

        在x86保護(hù)模式下,段的信息(段基線性地址、長(zhǎng)度、權(quán)限等)即段描述符占8個(gè)字節(jié),段信息無(wú)法直接存放在段寄存器中(段寄存器只有2字節(jié))。Intel的設(shè)計(jì)是段描述符集中存放在GDT或LDT中,而段寄存器存放的是段描述符在GDT或LDT內(nèi)的索引值(index)。

        Linux中邏輯地址等于線性地址。為什么這么說呢?因?yàn)長(zhǎng)inux所有的段(用戶代碼段、用戶數(shù)據(jù)段、內(nèi)核代碼段、內(nèi)核數(shù)據(jù)段)的線性地址都是從0x00000000開始,長(zhǎng)度4G,這樣線性地址=邏輯地址+ 0x00000000,也就是說邏輯地址等于線性地址了。

        前面說了Linux中邏輯地址等于線性地址,那么線性地址怎么對(duì)應(yīng)到物理地址呢?這個(gè)大家都知道,那就是通過分頁(yè)機(jī)制,具體的說,就是通過頁(yè)表查找來對(duì)應(yīng)物理地址。

        準(zhǔn)確的說分頁(yè)是CPU提供的一種機(jī)制,Linux只是根據(jù)這種機(jī)制的規(guī)則,利用它實(shí)現(xiàn)了內(nèi)存管理。

        在保護(hù)模式下,控制寄存器CR0的最高位PG位控制著分頁(yè)管理機(jī)制是否生效,如果PG=1,分頁(yè)機(jī)制生效,需通過頁(yè)表查找才能把線性地址轉(zhuǎn)換物理地址。如果PG=0,則分頁(yè)機(jī)制無(wú)效,線性地址就直接做為物理地址。

        分頁(yè)的基本原理是把內(nèi)存劃分成大小固定的若干單元,每個(gè)單元稱為一頁(yè)(page),每頁(yè)包含4k字節(jié)的地址空間(為簡(jiǎn)化分析,我們不考慮擴(kuò)展分頁(yè)的情況)。這樣每一頁(yè)的起始地址都是4k字節(jié)對(duì)齊的。為了能轉(zhuǎn)換成物理地址,我們需要給CPU提供當(dāng)前任務(wù)的線性地址轉(zhuǎn)物理地址的查找表,即頁(yè)表(page table)。注意,為了實(shí)現(xiàn)每個(gè)任務(wù)的平坦的虛擬內(nèi)存,每個(gè)任務(wù)都有自己的頁(yè)目錄表和頁(yè)表。

        為了節(jié)約頁(yè)表占用的內(nèi)存空間,x86將線性地址通過頁(yè)目錄表和頁(yè)表兩級(jí)查找轉(zhuǎn)換成物理地址。

        32位的線性地址被分成3個(gè)部分:

        最高10位Directory頁(yè)目錄表偏移量,中間10位Table是頁(yè)表偏移量,最低12位Offset是物理頁(yè)內(nèi)的字節(jié)偏移量。

        頁(yè)目錄表的大小為4k(剛好是一個(gè)頁(yè)的大小),包含1024項(xiàng),每個(gè)項(xiàng)4字節(jié)(32位),項(xiàng)目里存儲(chǔ)的內(nèi)容就是頁(yè)表的物理地址。如果頁(yè)目錄表中的頁(yè)表尚未分配,則物理地址填0。

        頁(yè)表的大小也是4k,同樣包含1024項(xiàng),每個(gè)項(xiàng)4字節(jié),內(nèi)容為最終物理頁(yè)的物理內(nèi)存起始地址。

        每個(gè)活動(dòng)的任務(wù),必須要先分配給它一個(gè)頁(yè)目錄表,并把頁(yè)目錄表的物理地址存入cr3寄存器。頁(yè)表可以提前分配好,也可以在用到的時(shí)候再分配。

        還是以mov0x80495b0, %eax中的地址為例分析一下線性地址轉(zhuǎn)物理地址的過程。

        前面說到Linux中邏輯地址等于線性地址,那么我們要轉(zhuǎn)換的線性地址就是0x80495b0。轉(zhuǎn)換的過程是由CPU自動(dòng)完成的,Linux所要做的就是準(zhǔn)備好轉(zhuǎn)換所需的頁(yè)目錄表和頁(yè)表(假設(shè)已經(jīng)準(zhǔn)備好,給頁(yè)目錄表和頁(yè)表分配物理內(nèi)存的過程很復(fù)雜,后面再分析)。

        內(nèi)核先將當(dāng)前任務(wù)的頁(yè)目錄表的物理地址填入cr3寄存器。

        線性地址0x80495b0轉(zhuǎn)換成二進(jìn)制后是0000 1000 0000 0100 1001 0101 1011 0000,最高10位0000 1000 00的十進(jìn)制是32,CPU查看頁(yè)目錄表第32項(xiàng),里面存放的是頁(yè)表的物理地址。線性地址中間10位00 0100 1001的十進(jìn)制是73,頁(yè)表的第73項(xiàng)存儲(chǔ)的是最終物理頁(yè)的物理起始地址。物理頁(yè)基地址加上線性地址中最低12位的偏移量,CPU就找到了線性地址最終對(duì)應(yīng)的物理內(nèi)存單元。

        我們知道Linux中用戶進(jìn)程線性地址能尋址的范圍是0-3G,那么是不是需要提前先把這3G虛擬內(nèi)存的頁(yè)表都建立好呢?一般情況下,物理內(nèi)存是遠(yuǎn)遠(yuǎn)小于3G的,加上同時(shí)有很多進(jìn)程都在運(yùn)行,根本無(wú)法給每個(gè)進(jìn)程提前建立3G的線性地址頁(yè)表。Linux利用CPU的一個(gè)機(jī)制解決了這個(gè)問題。進(jìn)程創(chuàng)建后我們可以給頁(yè)目錄表的表項(xiàng)值都填0,CPU在查找頁(yè)表時(shí),如果表項(xiàng)的內(nèi)容為0,則會(huì)引發(fā)一個(gè)缺頁(yè)異常,進(jìn)程暫停執(zhí)行,Linux內(nèi)核這時(shí)候可以通過一系列復(fù)雜的算法給分配一個(gè)物理頁(yè),并把物理頁(yè)的地址填入表項(xiàng)中,進(jìn)程再恢復(fù)執(zhí)行。當(dāng)然進(jìn)程在這個(gè)過程中是被蒙蔽的,它自己的感覺還是正常訪問到了物理內(nèi)存。

        但是頁(yè)又可以有不同的使用方式,所以內(nèi)核就引入?yún)^(qū)的概念,將頁(yè)劃分成為不同的區(qū):

        linux主要使用了四種區(qū):

        ZONE_DMA:這個(gè)區(qū)包含頁(yè)能用來執(zhí)行DMA操作。

        ZONE_DMA32:和ZONE_DMA類似,不過只能被32位設(shè)備訪問。

        ZONE_NORMAL:這個(gè)區(qū)包含的都是能正常映射的頁(yè)。

        ZONE_HIGHEM:包含“高端內(nèi)存”。

        這樣linux把系統(tǒng)劃分為區(qū),形成不同的內(nèi)存池從而用于不同的用途。注意:區(qū)的概念只不過是內(nèi)核的分配,而本身物理內(nèi)存是無(wú)法這樣分配的。


        上一頁(yè) 1 2 下一頁(yè)

        評(píng)論


        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 沧源| 潜山县| 英山县| 井冈山市| 承德县| 武宁县| 丽水市| 威信县| 固镇县| 奇台县| 金坛市| 南阳市| 清新县| 理塘县| 陵水| 武清区| 司法| 新营市| 柳江县| 桓台县| 上虞市| 东海县| 梁河县| 平江县| 乐清市| 浑源县| 南部县| 双鸭山市| 同江市| 陈巴尔虎旗| 沂源县| 旺苍县| 花莲县| 浦江县| 宝兴县| 固原市| 石景山区| 新昌县| 平和县| 梅州市| 得荣县|