旗下导航:搜·么
当前位置:网站首页 > PHP教程 > 正文

php中small内存规格的盘算(代码示例)【php教程】

作者:搜搜PHP网发布时间:2019-11-26分类:PHP教程浏览:99


导读:本篇文章给人人带来的内容是关于php中small内存规格的盘算(代码示例),有肯定的参考价值,有须要的朋侪能够参考一下,愿望对你有所协助。small内存分派盘算bin_nu...
本篇文章给人人带来的内容是关于php中small内存规格的盘算(代码示例),有肯定的参考价值,有须要的朋侪能够参考一下,愿望对你有所协助。

small内存分派盘算bin_num

在PHP源码中,有一段对small内存规格的盘算,细致在Zend/zend_alloc.c的zend_mm_small_size_to_bin函数中,其目标是传入一个size,盘算对应的规格。见代码:

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的状况是一个等差数列,递增8,所以运用size除以8就行(源码中是右移3位)size >> 3

  • 然则要斟酌到size即是8、16等的状况,所以为 (size - 1) >> 3

  • 然后要斟酌到为0的状况,所以源码中关于-1的处置惩罚是!!size,当size为0的状况!!0 = 0。所以当size为0的状况就把-1转换成了-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; 这个是边境状况,跟前面一样,背面涌现的size临时都以为已近减一了

  • 假定不看这个源码,我们要实如今ZEND_MM_BINS_INFO中找到对应的bin_num

  • ZEND_MM_BINS_INFO得知后续的增添4个为一组,分别为

2^4, 2^5, 2^6...
  • 有了这个分组信息的话,我们要找siez对应的bin_num

    • 找到这个size属于哪一组

    • 而且size在组内的偏移是多少

    • 盘算组的肇端位置

  • 那如今题目转换成了上面3个小题目,我们一个一个来处理

找到size属于哪一组
  • 最简朴的要领就是比大小是吧,能够运用if...else 来一个一个比,然则明显php源码不是如许干的,那我们另有什么别的的要领呢?

  • 我们看十进制看不出来什么花样,就把这些值转成二进制看看吧

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

.....
  • 我们看下上面的二进制,会发明每组的内的二进制长度相称,而且背面每一个都比前面多一名

  • 那就是说我们能够盘算二进制的长度来决议它的分组,那末二进制的长度又是啥呢,实在就是当前二进制的最高位为1的位数

  • 那末题目又转换成了求二进制中最高位的1的位数

  • 下面给出php源码的解法,这里临时不对其剖析,只需晓得它返回的是二进制中最高位的1的位数

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在组内的偏移量
  • 这个简朴,直接用size减去每组的肇端siez大小然后除以当前组内的差值(16、32、64...)即可,也就是(size-64)/16 (size-128)/32 (size-256)/64

  • 如今来看看上一步中的返回的值,每一个组分别是7、8、9...,那末我们如今来看看如许的数据怎样盘算组内的偏移量

(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,如许我们就能够依据它在哪一组的信息获得当前组的差值(16、32、64...)

  • 当size为65时,偏移量是否是就是

(64-64) / 2^4 = 0
盘算组的肇端位置
  • 如今我们有了偏移量的信息,假定我们分组是1、2、3

  • 那是否是就是用最高位的1的位数减去6就能够获得分组信息了

  • 获得分组信息以后,怎样晓得每组的肇端位置呢

  • 我们晓得肇端位置分别是8、12、16...它也是一个等差数列,就是4n+4

  • 我们在看看size=65的谁人例子

    • 盘算的偏移量是0

    • 盘算的肇端位置是4*1 + 4 = 8

    • 所以当size=65的bin_num就是肇端位置加上偏移量 8 + 0 = 8

  • 我们再看一个size=129的例子

    • 二进制中最高位的1的位数为8

    • 然后用8减去3获得5

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

    • 偏移量是

    • 盘算肇端位置是 4 * 2 + 4 = 12

    • 二者相加就是 12 + 0 = 0

  • size=193

    • 二进制中最高位的1的位数为8

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

    • 偏移量是

    • 盘算肇端位置是 4 * 2 + 4 = 12

    • 二者相加就是 12 + 2 = 14

  • size=1793

    • 二进制中最高位的1的位数为11

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

    • 偏移量是

    • 盘算肇端位置是 4 * 5 + 4 = 24

    • 二者相加就是 24 + 3 = 27

代码剖析

php完成代码

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;

  • 这里调用了zend_mm_small_size_to_bit这个函数,我们看看这个函数

/* 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;
  • 看解释我们就晓得这个函数是用来返回当前size二进制中最高位1的位数,细致的做法呢实在就是二分法

  • 我们经由过程zend_mm_small_size_to_bit这个函数猎取了size二进制中最高位1的位数,那末这个 -3 是什么奇异的操纵呢

    (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...

    • 上问的剖析中提到,我们盘算size在组内的偏移量的公式

第三行

  • t1 = t1 >> t2;

  • 把t1右移t2位,这又是什么奇异的操纵?

  • 这里我们把末了盘算bin_num的数学公式给写出来,它是即是每组的肇端位置加上组内的偏移量

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

以上就是php中small内存规格的盘算(代码示例)的细致内容,更多请关注ki4网别的相干文章!

标签:php