php中small内存规格的计算(代码示例)

php中small内存规格的计算(代码示例)

内容导读

收集整理的这篇技术教程文章主要介绍了php中small内存规格的计算(代码示例),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6439字,纯文字阅读大概需要10分钟

内容图文

本篇文章给大家带来的内容是关于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 000080
| 101 000096
| 110 0000112 | 111 0000128 | 1000 0000160 | 1010 0000192 | 1100 0000224 | 1110 0000256 | 1 0000 0000320 | 1 0100 0000384 | 1 1000 0000448 | 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内存规格的计算(代码示例)的详细内容,更多请关注Gxl网其它相关文章!

内容总结

以上是为您收集整理的php中small内存规格的计算(代码示例)全部内容,希望文章能够帮你解决php中small内存规格的计算(代码示例)所遇到的程序开发问题。 如果觉得技术教程内容还不错,欢迎将网站推荐给程序员好友。

内容备注

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。


本文关键词:

联系我们

在线咨询:点击这里给我发消息

邮件:w420220301@qq.com