国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【PHP源碼學習】2019-03-08 PHP內存管理2筆記

Winer / 2641人閱讀

摘要:用表達式表示以上結論或者結構體內存對齊核心結論它是編譯器做的優化,空間換時間的思想。整個聯合體占用的空是所有字段多帶帶占用空間大小中取占用空間大小最大的字段。使用命令繼續運行我們可以看到上有項已經不是了,說明上次分配過內存。

baiyan

全部視頻:https://segmentfault.com/a/11...

源視頻地址:http://replay.xesv5.com/ll/24...

復習

宏的用法:

typedef struct _zend_alloc_globals {
    zend_mm_heap *mm_heap;
} zend_alloc_globals;
...
# define AG(v) (alloc_globals.v)
static zend_alloc_globals alloc_globals;

這個帶有參數的宏取得zend_alloc_globals結構體類型里的zend_mm_heap結構體字段,如AG(mm_heap) = alloc_globals.mm_heap

宏就是替換。

結構體與結構體內存對齊 結構體

先看一段結構體代碼struct.c:

#include 
int main() {
    struct a{
        char a;
        int b;
        long c;
        void *d;
        int e;
        char *f;
    }s;
    s.a = "c";
    s.b = 1;
    s.c = 22l;
    s.d = NULL;
    s.e = 1;
    s.f = &s.a;
    printf("sizeof struct a is %d", (int)sizeof(s));
}

編譯:gcc -g struct.c -o struct

運行:./struct,sizeof(a)的打印結果為:40

對這個結構體進行gdb調試:

在這里我們可以看到第一行是所有結構體變量的初始值,注意指針變量是一個隨機的地址,在給s.d賦值的過程中,地址變成了0x0,它是一個特殊的地址值,代表NULL。

除此之外,我們注意到結構體s的地址和a變量的地址是相同的。

用表達式表示以上結論:&s = &s.a = f或者s = s.a = *f

結構體內存對齊

核心結論:它是編譯器做的優化,空間換時間的思想。

對齊方式:按照結構體所有字段的最小公倍數做對齊(最小公倍數是8B就按8B對齊;是4B就按4B對齊),且與結構體字段的排列順序是相關。如圖:

我們利用gdb驗證一下以上的結論,還是利用上述同樣的代碼:

我們看到變量a的起始地址是150,而b的地址是154,顯然做了對齊。如果不對齊,b的地址應該為151,說明a和b中間空了3B的大小。c的地址是158,就是下一個8B的起始地址,而d的地址是160(注意這里是16進制,158+8 = 160的時候才會進位),證明了c占用了8B,下面d變量也同理占用了8B。注意e變量,它是一個int,如果不對齊應該只占用4B。而它占用了170(f的起始地址)- 168(e的起始地址) = 8B,所以一定是做了內存對齊的。

注意一個特例:如果b是一個char類型,那么是直接緊跟在上一個char后面,如圖:

注意這里的地址均為邏輯地址,每次編譯后的邏輯地址是相同的,而物理地址是不同的。

注意:如果調換順序,把b和c調換位置,就會變成8B(a)+8B(c)+8B(b)+8B(d)+8B(e)+8B(f) = 48B

注意:一定是所有字段的最小公倍數是幾字節,就按幾字節對齊,我們看一下結構體中只有char類型變量的情況:

#include 
int main() {
    struct a{
        char a;
        char b;
        char c;
    }s;
    s.a = "c";
    s.b = "b";
    s.c = "a";
    printf("sizeof struct a is %d
", (int)sizeof(s));
}

這個結構體中只有char類型變量

編譯運行,輸出sizeof(s)的結果為:3

為什么不是4或者8?因為1,1,1的最小公倍數就是1,就按照1B來對齊,而不是4B、8B

同理,如果都是int類型的變量,那么sizeof(s)的結果為12,也很好理解了

聯合體

核心結論:所有聯合體字段共用一塊內存空間。整個聯合體占用的空是所有字段多帶帶占用空間大小中取占用空間大小最大的字段。

同樣先看一段代碼:

#include 
int main() {
    union a{
        char a;
        int b;
        long c;
        void *d;
        int e;
        char *f;
    }s;
    s.a = "c";
    s.b = 1;
    s.c = 22l;
    s.d = NULL;
    s.e = 1;
    s.f = &s.a;
    printf("sizeof struct a is %d", (int)sizeof(s));
}

這段代碼與上段結構體的代碼只將struct修改為union,其他均不變

編譯運行,輸出sizeof(a)的結果為:8

我們利用gdb調試一下這段代碼:

我們可以看到,后面的變量一賦值,就會覆蓋前面的變量值

再看一下每個變量的地址,我們可以清楚地看到,所有變量的起始地址都是一樣的。

其他

思考:一個void *類型的變量,能否直接取它的內容?答案:不可以,其他有類型的指針變量可以取內容是因為記錄了當前類型的長度,而void *類型沒有長度,無法直接取,除非使用強制類型轉換或者指定長度。

延伸:PHP所有變量基于zval,zval就是由3個聯合體組成(zend_value,u1,u2)這里不展開

大小端:

大端:也叫高尾端,即數據尾端(低位)放在高地址

小端:也叫低尾端,即數據尾端(低位)放在低地址

網絡字節序是大端的

網絡字節序是大端的,所以小端機器需要對收到或發出的數據包進行大小端的轉換

如何判斷是大端還是小端:參考:判斷機器大小端的兩種實現方式

利用指針:int為4個字節,通過強轉成char類型,取低1個字節,如果恰好是0x78,那就說明低1個字節恰好存在低地址,為小端。如果取低1個字節的結果是0x12,低1個字節存在高地址,為大端。

int main() {
    int i = 0x12345678;
    if (*(char*)&i == 78) {
        printf("小端");
    } else {
        printf("大端");
    }
}

利用聯合體:本質思想和指針方法相同,利用了聯合體共用同一塊存儲空間的特性。

int main() {
    union w{
        int a;
        char b;
    }c;
    c.a = 1;
    if (c.b == 1) {
        printf("小端");
    } else {
        printf("大端");
    }
}

利用gdb觀察PHP內存分配時的情況,示例代碼:


gdb php并在_emalloc()處打斷點,運行代碼:

我們可以清晰地看到mm_heap這個變量,它在small、large內存中存儲一些額外的page分配信息等等。其中比較重要的size、peak、free_slot、main_chunk等變量。free_slot數組暫時還是空。再看mm_heap中的main_chunk字段,它來表示一個chunk,是一個雙向鏈表。第一個字段heap是一個指向zend_mm_heap的指針,可以快速找到第一個記錄信息的page,并且可以發現它的地址和上面直接打印alloc_globals.mm_heap的地址是相同的。再觀察free_map字段,它由8個個uint64類型組成,代表各個page的使用情況,這里第1個page存了zend_mm_heap結構體,已經被使用。再看map字段,它是一個數組,大小為512,每個都是uint32類型,打印數組第一項的值,以16進制表示為0x40000001,代表large內存,最后一位是1,代表分配1個page。

使用c命令繼續運行:

我們可以看到free_slot上有3項已經不是0x0了,說明上次分配過small內存。且現在free_map的值發生了變化,而map說明第1、2、3、4、9頁已經被使用了,那么為什么中間有幾個0呢,是因為第4個map值,按照16進制打印為0x40000005,是large內存,且需要分配5個頁,所以后面的4個頁都是0。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/31267.html

相關文章

  • 【LNMPR源碼學習筆記匯總

    摘要:此文用于匯總跟隨陳雷老師及團隊的視頻,學習源碼過程中的思考整理與心得體會,此文會不斷更新視頻傳送門每日學習記錄使用錄像設備記錄每天的學習源碼學習源碼學習內存管理筆記源碼學習內存管理筆記源碼學習內存管理筆記源碼學習基本變量筆記 此文用于匯總跟隨陳雷老師及團隊的視頻,學習源碼過程中的思考、整理與心得體會,此文會不斷更新 視頻傳送門:【每日學習記錄】使用錄像設備記錄每天的學習 PHP7...

    Barrior 評論0 收藏0
  • 【每日學習記錄】使用錄像設備記錄每天的學習

    摘要:在這里使用學而思網校的錄像設備,記錄每天學習的內容執行潘森執行潘森執行潘森趙俊峰紅黑樹景羅紅黑樹景羅配置三叉樹田志澤新建模塊馬運運配置田志澤田志澤田志澤李樂田志澤田志澤文件系統 在這里使用學而思網校的錄像設備,記錄每天學習的內容: 2019-07-15 ~ 2019-07-19 07-18 nginx http 執行 by 潘森 07-17 nginx http 執行 by 潘森 07...

    pkhope 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<