目录
对于size小于等于64的情况
对于size大于64的情况
初始懵逼
步骤分析
找到size属于哪一组
计算size在组内的偏移量
计算组的起始位置
代码分析
php实现代码
第一行
第二行
第三行
第四行
第五行
第六行
首页 后端开发 php教程 php中small内存规格的计算(代码示例)

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

Feb 25, 2019 am 10:01 AM
php

本篇文章给大家带来的内容是关于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</pre> <li><p>但是要考虑到size等于8、16等的情况,所以为 <code>(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;</pre> <li><p>把t1右移t2位,这又是什么神奇的操作?</p></li> <li><p>这里我们把最后计算bin_num的数学公式给写出来,它是等于每组的起始位置加上组内的偏移量</p></li> <div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">binnum = (4n + 4) + (size / 2^n - 4) binnum = 4n + size / 2^n</pre><div class="contentsignin">登录后复制</div></div><div class="contentsignin">登录后复制</div></div> <ul class=" list-paddingleft-2"><li><p>所以第三行的意思我们就知道了,就是size右移2^n次方为</p></li></ul> <h4 id="第四行">第四行</h4> <ul class=" list-paddingleft-2"> <li><p><code>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内存规格的计算(代码示例)的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

适用于 Ubuntu 和 Debian 的 PHP 8.4 安装和升级指南 适用于 Ubuntu 和 Debian 的 PHP 8.4 安装和升级指南 Dec 24, 2024 pm 04:42 PM

PHP 8.4 带来了多项新功能、安全性改进和性能改进,同时弃用和删除了大量功能。 本指南介绍了如何在 Ubuntu、Debian 或其衍生版本上安装 PHP 8.4 或升级到 PHP 8.4

我后悔之前不知道的 7 个 PHP 函数 我后悔之前不知道的 7 个 PHP 函数 Nov 13, 2024 am 09:42 AM

如果您是一位经验丰富的 PHP 开发人员,您可能会感觉您已经在那里并且已经完成了。您已经开发了大量的应用程序,调试了数百万行代码,并调整了一堆脚本来实现操作

如何设置 Visual Studio Code (VS Code) 进行 PHP 开发 如何设置 Visual Studio Code (VS Code) 进行 PHP 开发 Dec 20, 2024 am 11:31 AM

Visual Studio Code,也称为 VS Code,是一个免费的源代码编辑器 - 或集成开发环境 (IDE) - 可用于所有主要操作系统。 VS Code 拥有针对多种编程语言的大量扩展,可以轻松编写

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

您如何在PHP中解析和处理HTML/XML? 您如何在PHP中解析和处理HTML/XML? Feb 07, 2025 am 11:57 AM

本教程演示了如何使用PHP有效地处理XML文档。 XML(可扩展的标记语言)是一种用于人类可读性和机器解析的多功能文本标记语言。它通常用于数据存储

php程序在字符串中计数元音 php程序在字符串中计数元音 Feb 07, 2025 pm 12:12 PM

字符串是由字符组成的序列,包括字母、数字和符号。本教程将学习如何使用不同的方法在PHP中计算给定字符串中元音的数量。英语中的元音是a、e、i、o、u,它们可以是大写或小写。 什么是元音? 元音是代表特定语音的字母字符。英语中共有五个元音,包括大写和小写: a, e, i, o, u 示例 1 输入:字符串 = "Tutorialspoint" 输出:6 解释 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。总共有 6 个元

解释PHP中的晚期静态绑定(静态::)。 解释PHP中的晚期静态绑定(静态::)。 Apr 03, 2025 am 12:04 AM

静态绑定(static::)在PHP中实现晚期静态绑定(LSB),允许在静态上下文中引用调用类而非定义类。1)解析过程在运行时进行,2)在继承关系中向上查找调用类,3)可能带来性能开销。

什么是PHP魔术方法(__ -construct,__destruct,__call,__get,__ set等)并提供用例? 什么是PHP魔术方法(__ -construct,__destruct,__call,__get,__ set等)并提供用例? Apr 03, 2025 am 12:03 AM

PHP的魔法方法有哪些?PHP的魔法方法包括:1.\_\_construct,用于初始化对象;2.\_\_destruct,用于清理资源;3.\_\_call,处理不存在的方法调用;4.\_\_get,实现动态属性访问;5.\_\_set,实现动态属性设置。这些方法在特定情况下自动调用,提升代码的灵活性和效率。

See all articles