Calcul de petites spécifications de mémoire en php (exemple de code)

不言
Libérer: 2023-04-05 11:50:02
avant
2141 Les gens l'ont consulté

Ce que cet article vous apporte concerne le calcul des petites spécifications de mémoire en PHP (exemples de code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Calcul d'allocation de petite mémoire bin_num

Dans le code source PHP, il y a un calcul de spécifications de petite mémoire, spécifiquement dans la fonction zend_mm_small_size_to_bin de Zend/zend_alloc.c, son but est de passer une taille, calculez les spécifications correspondantes. Voir le code :

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);
}
Copier après la connexion

On voit que ce code est divisé en deux situations à discuter :

  • 1 Le cas où la taille est inférieure ou supérieure. égal à 64 ;

  • 2. Le cas où la taille est supérieure à 64 ;

Analysons ces deux situations en détail ci-dessous.

Pour le cas où la taille est inférieure ou égale à 64

  • VoirZEND_MM_BINS_INFOCette macro sait que lorsque la taille est inférieure ou égale à 64, elle est une séquence arithmétique, incrémentée de 8, donc utilisez Divisez simplement la taille par 8 (elle est décalée de 3 chiffres vers la droite dans le code source) size >> 3</pre> <li> <p>Mais il faut considérer la situation où la taille est égale à 8, 16, etc., donc c'est <code>(size - 1) >> 3

  • Ensuite il faut considérer le cas de 0, donc le traitement de -1 dans le code source est !!size, et lorsque la taille est 0, !!0 = 0. Ainsi lorsque la taille est 0, -1 est converti en -0, et enfin il y a l'expression dans le code source (size - !!size) >> 3

  • pour le cas où la taille est plus grande que 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);
    Copier après la connexion

    Confusion initiale

    • Lorsque vous regardez ce code pour la première fois, il est facile de se tromper. Que sont ces t1 t2 ?

    • Mais n'ayez pas peur, analysons-le étape par étape

    Analyse des étapes

    /* 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 */
    Copier après la connexion
    • size = size - 1; Il s'agit d'une situation limite, similaire à la précédente. De même, la taille qui apparaît plus tard est considérée comme ayant été réduite de un pour le moment

    • En supposant que ce ne soit pas le cas. regardez ce code source, nous devons trouver le bin_num correspondantZEND_MM_BINS_INFO

      dans
    • On sait de ZEND_MM_BINS_INFO que les 4 groupes suivants seront ajoutés en tant que groupe, respectivement

    2^4, 2^5, 2^6...
    Copier après la connexion
    • Avec ces informations de regroupement, nous devons trouver le bin_num correspondant à siez

      • pour trouver à quel groupe appartient cette taille

      • et le décalage de la taille au sein du groupe Quelle est la position de départ du groupe calculé À résoudre

      • trouver à quelle taille de groupe appartient

    • Le moyen le plus simple est de comparer la taille, n'est-ce pas Vous pouvez utiliser if...else Comparez un par un, mais évidemment le code source PHP ? ne fonctionne pas de cette façon, alors quelles autres méthodes avons-nous ?

    Nous ne voyons rien d'intéressant en décimal, alors convertissons ces valeurs en binaire et jetons un œil
    • Si nous regardons les nombres binaires ci-dessus, nous constaterons que les longueurs des nombres binaires dans chaque groupe sont égales, et chacun des nombres suivants a un chiffre de plus que le précédent
    • C'est-à-dire qu'on peut calculer le nombre binaire. La longueur détermine son regroupement, alors quelle est la longueur du système binaire. En fait, c'est le nombre de chiffres où se trouve le bit le plus élevé du courant ? le système binaire est
    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
    
    .....
    Copier après la connexion
    • Ensuite, le problème est converti en trouvant le système binaire Le nombre de chiffres du

      le plus élevé dans
    • <. 🎜>La solution au code source PHP est donnée ci-dessous. Nous ne l'analyserons pas ici pour le moment. Sachez simplement qu'il renvoie le 1 le plus élevé du binaire

    • <🎜. >
    • 1

      Supposons que la taille pour laquelle nous postulons est de 65, alors n renvoie ici 7
    • 1 Calcul du décalage de taille au sein du groupe

    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;
    Copier après la connexion
    est simple. Soustrayez simplement la taille de départ de chaque groupe de la taille, puis divisez-la par la différence dans le groupe actuel (16, 32, 64...), c'est-à-dire
    • Jetons maintenant un œil à la valeur renvoyée à l'étape précédente Chaque groupe est
    , alors faisons-le maintenant. Voyons comment calculer le décalage au sein du groupe. avec des données comme celle-ci
    • (size-64)/16 (size-128)/32 (size-256)/64

      Pouvons-nous soustraire
    • de
    • pour obtenir

      , afin que nous puissions obtenir la différence des groupe actuel (16, 32, 64...) en fonction des informations sur le groupe dans lequel il se trouve. 7、8、9...

    Lorsque la taille est de 65, le décalage est le montant juste
    (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
    Copier après la connexion
    • 7、8、9 Calculez la position de départ du groupe 34、5、6

    • Nous avons maintenant les informations de décalage, en supposant que nous regroupons C'est 1, 2, 3
    • Ensuite, vous pouvez obtenir les informations de regroupement en soustrayant
    du nombre de chiffres du plus haut
    (64-64) / 2^4 = 0
    Copier après la connexion
    • Après avoir obtenu les informations de regroupement, comment connaître la position de départ de chaque groupe ?

    • Nous savons que les positions de départ sont respectivement

      C'est aussi une suite arithmétique, qui est16

    • Nous regardons l'exemple de taille=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);
    Copier après la connexion

    第一行

    • 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;
    Copier après la connexion
    • 看注释我们就知道这个函数是用来返回当前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
      Copier après la connexion
      • 这里获取二进制的位数是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">Copier après la connexion</div></div><div class="contentsignin">Copier après la connexion</div></div> <ul class=" list-paddingleft-2"><li><p>所以第三行的意思我们就知道了,就是size右移2^n次方为</p></li></ul> <h4>第四行</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
    Copier après la connexion
    Copier après la connexion
    • 那么这行就好理解了,就是计算每组的起始位置4n对吧,左移两位就是乘以4

    第六行

    • return (int)(t1 + t2);

    • 这行没啥说的,就是返回了一个int类型的bin_num

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
php
source:segmentfault.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!