成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【PHP源碼分析】small內(nèi)存規(guī)格的計算

waltr / 2504人閱讀

摘要:作者李德內(nèi)存分配計算在源碼中,有一段對內(nèi)存規(guī)格的計算,具體在的函數(shù)中,其目的是傳入一個,計算對應的規(guī)格。見代碼可以看出,這段代碼中分為兩種情況進行討論小于等于的情況大于的情況下面我們對這兩種情況詳細分析下。

作者:李德

small內(nèi)存分配計算bin_num

在PHP源碼中,有一段對small內(nèi)存規(guī)格的計算,具體在Zend/zend_alloc.c的zend_mm_small_size_to_bin函數(shù)中,其目的是傳入一個size,計算對應的規(guī)格。見代碼:

if (size <= 64) {
    /* we need to support size == 0 ... */
    return (size - !!size) >> 3;
} else {
    t1 = size - 1;
    t2 = zend_mm_small_size_to_bit(t1) - 3;
    t1 = t1 >> t2;
    t2 = t2 - 3;
    t2 = t2 << 2;
    return (int)(t1 + t2);
}

可以看出,這段代碼中分為兩種情況進行討論:

1、size小于等于64的情況;

2、size大于64的情況;

下面我們對這兩種情況詳細分析下。

對于size小于等于64的情況

ZEND_MM_BINS_INFO這個宏知道當size小于等于64的情況是一個等差數(shù)列,遞增8,所以使用size除以8就行(源碼中是右移3位)size >> 3

但是要考慮到size等于8、16等的情況,所以為 (size - 1) >> 3

然后要考慮到為0的情況,所以源碼中對于-1的處理是!!size,當size為0的情況!!0 = 0。所以當size為0的情況就把-1轉(zhuǎn)換成了-0,最終有了源碼中的表達式 (size - !!size) >> 3

對于size大于64的情況
t1 = size - 1;
t2 = zend_mm_small_size_to_bit(t1) - 3;
t1 = t1 >> t2;
t2 = t2 - 3;
t2 = t2 << 2;
return (int)(t1 + t2);
初始懵逼

初看這個代碼,容易一臉懵逼,這些t1 t2 都是啥啊

不過不用怕,我們一點點來分析

步驟分析
/* num, size, count, pages */
#define ZEND_MM_BINS_INFO(_, x, y) 
    _( 0,    8,  512, 1, x, y) 
    _( 1,   16,  256, 1, x, y) 
    _( 2,   24,  170, 1, x, y) 
    _( 3,   32,  128, 1, x, y) 
    _( 4,   40,  102, 1, x, y) 
    _( 5,   48,   85, 1, x, y) 
    _( 6,   56,   73, 1, x, y) 
    _( 7,   64,   64, 1, x, y) 
   
    _( 8,   80,   51, 1, x, y) 
    _( 9,   96,   42, 1, x, y) 
    _(10,  112,   36, 1, x, y)     
    _(11,  128,   32, 1, x, y) 
    
    _(12,  160,   25, 1, x, y)     
    _(13,  192,   21, 1, x, y) 
    _(14,  224,   18, 1, x, y)     
    _(15,  256,   16, 1, x, y) 
    
    _(16,  320,   64, 5, x, y)     
    _(17,  384,   32, 3, x, y) 
    _(18,  448,    9, 1, x, y)     
    _(19,  512,    8, 1, x, y) 
    
    _(20,  640,   32, 5, x, y) 
    _(21,  768,   16, 3, x, y) 
    _(22,  896,    9, 2, x, y)     
    _(23, 1024,    8, 2, x, y) 
    
    _(24, 1280,   16, 5, x, y) 
    _(25, 1536,    8, 3, x, y) 
    _(26, 1792,   16, 7, x, y)     
    _(27, 2048,    8, 4, x, y) 
    
    _(28, 2560,    8, 5, x, y) 
    _(29, 3072,    4, 3, x, y)

#endif /* ZEND_ALLOC_SIZES_H */

size = size - 1; 這個是邊界情況,跟前面一樣,后面出現(xiàn)的size暫且都認為已近減一了

假設不看這個源碼,我們要實現(xiàn)在ZEND_MM_BINS_INFO中找到對應的bin_num

ZEND_MM_BINS_INFO得知后續(xù)的增加4個為一組,分別為

2^4, 2^5, 2^6... 

有了這個分組信息的話,我們要找siez對應的bin_num

找到這個size屬于哪一組

并且size在組內(nèi)的偏移是多少

計算組的起始位置

那現(xiàn)在問題轉(zhuǎn)換成了上面3個小問題,我們一個一個來解決

找到size屬于哪一組

最簡單的辦法就是比大小是吧,可以使用if...else 來一個一個比,但是顯然php源碼不是這樣干的,那我們還有什么其它的辦法呢?

我們看十進制看不出來什么名堂,就把這些值轉(zhuǎn)成二進制看看吧

64  | 100 0000
80  | 101 0000
96  | 110 0000
112 | 111 0000

128 | 1000 0000
160 | 1010 0000
192 | 1100 0000
224 | 1110 0000

256 | 1 0000 0000
320 | 1 0100 0000
384 | 1 1000 0000
448 | 1 1100 0000

.....

我們看下上面的二進制,會發(fā)現(xiàn)每組內(nèi)的二進制長度相等,并且后面每個都比前面多一位

那就是說我們可以計算二進制的長度來決定它的分組,那么二進制的長度又是啥呢,其實就是當前二進制的最高位為1的位數(shù)

那么問題又轉(zhuǎn)換成了求二進制中最高位的1的位數(shù)

下面給出php源碼的解法,這里暫時不對其解析,只要知道它返回的是二進制中最高位的1的位數(shù)

int n = 16;
if (size <= 0x00ff) {n -= 8; size = size << 8;}
if (size <= 0x0fff) {n -= 4; size = size << 4;}
if (size <= 0x3fff) {n -= 2; size = size << 2;}
if (size <= 0x7fff) {n -= 1;}
return n;

假設我們申請的size為65,那么這里的n返回7

計算size在組內(nèi)的偏移量

這個簡單,直接用size減去每組的起始siez大小然后除以當前組內(nèi)的差值(16、32、64...)即可,也就是(size-64)/16 (size-128)/32 (size-256)/64

現(xiàn)在來看看上一步中的返回的值,每個組分別是7、8、9...,那么我們現(xiàn)在來看看這樣的數(shù)據(jù)怎么計算組內(nèi)的偏移量

(size - 2^4 * 4) / 16 = size / 2^4 - 4

(size - 2^5 * 4) / 32 = size / 2^5 - 4   

(size - 2^6 * 4) / 64 = szie / 2^6 - 4

那是不是可以用7、8、9減去3得到4、5、6,這樣我們就可以根據(jù)它在哪一組的信息得到當前組的差值(16、32、64...)

當size為65時,偏移量是不是就是

(65-64) / 2^4 = 0
計算組的起始位置

現(xiàn)在我們有了偏移量的信息,假定我們分組是1、2、3

那是不是就是用最高位的1的位數(shù)減去6就可以得到分組信息了

得到分組信息之后,怎么知道每組的起始位置呢

我們知道起始位置分別是8、12、16...它也是一個等差數(shù)列,就是4n+4

我們在看看size=65的那個例子

計算的偏移量是0

計算的起始位置是4*1 + 4 = 8

所以當size=65的bin_num就是起始位置加上偏移量 8 + 0 = 8

我們再看一個size=129的例子

偏移量是

二進制中最高位的1的位數(shù)為8

然后用8減去3得到5

(129 - 1 - 32 * 4) / 64 = 0

計算起始位置是 4 * 2 + 4 = 12

兩者相加就是 12 + 0 = 0

size=193

偏移量是

二進制中最高位的1的位數(shù)為8

(193 - 1 - 32 * 4) / 64 = 2

計算起始位置是 4 * 2 + 4 = 12

兩者相加就是 12 + 2 = 14

size=1793

偏移量是

二進制中最高位的1的位數(shù)為11

(1793 - 1 - 256 * 4) / 256 = 3

計算起始位置是 4 * 5 + 4 = 24

兩者相加就是 24 + 3 = 27

代碼分析 php實現(xiàn)代碼
1 t1 = size - 1;
2 t2 = zend_mm_small_size_to_bit(t1) - 3;
3 t1 = t1 >> t2;
4 t2 = t2 - 3;
5 t2 = t2 << 2;
6 return (int)(t1 + t2);
第一行

t1 = size - 1;

是為了考慮size為64、128...這些邊界情況

第二行

t2 = zend_mm_small_size_to_bit(t1) - 3;

這里調(diào)用了zend_mm_small_size_to_bit這個函數(shù),我們看看這個函數(shù)

/* higher set bit number (0->N/A, 1->1, 2->2, 4->3, 8->4, 127->7, 128->8 etc) */

int n = 16;
if (size <= 0x00ff) {n -= 8; size = size << 8;}
if (size <= 0x0fff) {n -= 4; size = size << 4;}
if (size <= 0x3fff) {n -= 2; size = size << 2;}
if (size <= 0x7fff) {n -= 1;}
return n;

看注釋我們就知道這個函數(shù)是用來返回當前size二進制中最高位1的位數(shù),具體的做法呢其實就是二分法

我們通過zend_mm_small_size_to_bit這個函數(shù)獲取了size二進制中最高位1的位數(shù),那么這個 -3 是什么神奇的操作呢

上問的分析中提到,我們計算size在組內(nèi)的偏移量的公式

(size - 2^4 * 4) / 16 = size / 2^4 - 4  

(size - 2^5 * 4) / 32 = size / 2^5 - 4 

(size - 2^6 * 4) / 64 = szie / 2^6 - 4

這里獲取二進制的位數(shù)是7、8、9...通過 -3 的操作來獲取相應的 4、5、6...

第三行

t1 = t1 >> t2;

把t1右移t2位,這又是什么神奇的操作?

這里我們把最后計算bin_num的數(shù)學公式給寫出來,它是等于每組的起始位置加上組內(nèi)的偏移量

binnum = (4n + 4) + (size / 2^n - 4)

binnum = 4n + size / 2^n

所以第三行的意思我們就知道了,就是size右移2^n次方為

第四行

t2 = t2 - 3;

這個好理解,可以參照上文得到每組的起始位置的方法

第五行

t2 = t2 << 2;

我們再看看bin_num的計算公式

binnum = (4n + 4) + (size / 2^n - 4)

binnum = 4n + size / 2^n

那么這行就好理解了,就是計算每組的起始位置4n對吧,左移兩位就是乘以4

第六行

return (int)(t1 + t2);

這行沒啥說的,就是返回了一個int類型的bin_num

文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/30163.html

相關文章

  • PHP7源碼分析PHP內(nèi)存管理

    摘要:分頁管理先說說虛擬內(nèi)存的概念。每個存在的虛擬頁面都保存在某個區(qū)域中,不屬于任何一個區(qū)域的虛擬頁是不存在的,不能被進程使用內(nèi)核為系統(tǒng)中的每個進程維護一個單獨的任務結構,任務中的一個字段指向,他描述了虛擬內(nèi)存的當前狀態(tài)。 作者: 順風車運營研發(fā)團隊 李樂 第一章 從操作系統(tǒng)內(nèi)存管理說起 程序是代碼和數(shù)據(jù)的集合,進程是運行著的程序;操作系統(tǒng)需要為進程分配內(nèi)存;進程運行完畢需要釋放內(nèi)存;內(nèi)存管...

    waltr 評論0 收藏0
  • PHP源碼學習】2019-03-07 PHP內(nèi)存管理1筆記

    摘要:換句話說,盡量不要有內(nèi)存碎片。例如分配的內(nèi)存,不能只分配個,因為會剩下大小的內(nèi)存碎片,不能夠再次利用并分配。但是如果最小公倍數(shù)過大,導致所需要的太多,那么退而求其次,即使留有很少的內(nèi)存碎片,也算是可以滿足需求的。同時也避免了內(nèi)存碎片的產(chǎn)生。 baiyan 全部視頻:https://segmentfault.com/a/11... 源視頻地址:http://replay.xesv5.co...

    shiyang6017 評論0 收藏0
  • (PHP7內(nèi)核剖析-9) 內(nèi)存管理

    摘要:但在多線程模式下會有多個,也就是說每個線程都有一個獨立的內(nèi)存池內(nèi)存分配分配超過內(nèi)存的申請,與通用的內(nèi)存申請沒有太大差別,只是將申請的內(nèi)存塊通過單鏈表進行了管理。的分配實際就是分配多個,的分配也是內(nèi)存分配的基礎,它是向系統(tǒng)申請內(nèi)存的唯一粒度。 1.Zend內(nèi)存池 內(nèi)存池是內(nèi)核中最底層的內(nèi)存操作,定義了三種粒度的內(nèi)存塊:chunk、page、slot,每個chunk的大小為2M,page大...

    ygyooo 評論0 收藏0
  • PHP源碼學習】2019-03-11 PHP內(nèi)存管理3筆記

    摘要:那么問題來了,為什么要把如此簡單的一個數(shù)組初始化問題復雜化這樣寫代碼真的真的不會被別人錘嗎其實源碼中還有其他相關部分我們可以看到,源碼中提供了三個類似的宏替換結構。 baiyan 全部視頻:https://segmentfault.com/a/11... 源視頻地址:http://replay.xesv5.com/ll/24... 復習 PHP內(nèi)存分配流程 showImg(https:...

    wangjuntytl 評論0 收藏0
  • 鴻蒙輕內(nèi)核源碼分析:虛實映射

    摘要:處設置內(nèi)核地址空間的映射。內(nèi)核虛擬地址空間是固定映射到物理內(nèi)存的。處按指定的標簽對段之前的內(nèi)存區(qū)間進行虛實映射。 摘要:本文介紹了MMU虛實映射的基本概念,運行機制,分析了映射初始化、映射查詢、映射虛擬內(nèi)存和物理內(nèi)存,解除虛實映射,更改映射屬性,重新映射等常用接口的代碼。本文分享自華為云社區(qū)??《使用MRS CDL實現(xiàn)實時...

    不知名網(wǎng)友 評論0 收藏0

發(fā)表評論

0條評論

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