Heim  >  Artikel  >  Backend-Entwicklung  >  Berechnung kleiner Speicherspezifikationen in PHP (Codebeispiel)

Berechnung kleiner Speicherspezifikationen in PHP (Codebeispiel)

不言
不言nach vorne
2019-02-25 10:01:162170Durchsuche

In diesem Artikel geht es um die Berechnung kleiner Speicherspezifikationen in PHP (Codebeispiele). Ich hoffe, dass er für Freunde hilfreich ist.

Berechnung der kleinen Speicherzuweisung bin_num

Im PHP-Quellcode gibt es eine Berechnung kleiner Speicherspezifikationen, insbesondere in der Funktion zend_mm_small_size_to_bin von Zend/zend_alloc.c, deren Zweck die Übergabe ist eine Größe, berechnen Sie die entsprechenden Spezifikationen. Siehe den 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);
}

Es ist ersichtlich, dass dieser Code zur Diskussion in zwei Situationen unterteilt ist:

  • 1. Der Fall, in dem die Größe kleiner oder gleich ist 64;

  • Der Fall, in dem die Größe größer als 64 ist;

Lassen Sie uns diese beiden Situationen im Detail analysieren.

Für den Fall, dass die Größe kleiner oder gleich 64 ist

  • SieheZEND_MM_BINS_INFODieses Makro weiß, dass die Größe kleiner oder gleich 64 ist eine arithmetische Folge, die um 8 inkrementiert wird, also verwenden Sie einfach die Größe durch 8 (sie wird im Quellcode um 3 Ziffern nach rechts verschoben) size >> 3</pre> <li> <p>Aber wir müssen die Situation berücksichtigen, in der Größe ist gleich 8, 16 usw., also ist es <code>(size - 1) >> 3

  • Dann müssen wir den Fall von 0 berücksichtigen, also die Verarbeitung von -1 im Quellcode ist !!size, und wenn die Größe 0 ist, !!0 = 0. Wenn die Größe also 0 ist, wird -1 in -0 umgewandelt, und schließlich gibt es im Quellcode den Ausdruck (size - !!size) >> 3

  • für den Fall, dass die Größe größer ist als 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);

    Anfängliche Verwirrung

    • Auf den ersten Blick kann man bei diesem Code leicht verwirrt werden. Was sind diese t1 t2?

    • Aber keine Angst, lass es uns Schritt für Schritt analysieren

    Schrittanalyse

    /* 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; Das ist ein Grenzsituation, genau wie die vorherige, wird später erscheinen. Derzeit wird angenommen, dass die Größe um fast eins reduziert wurde

    • Vorausgesetzt, wir schauen uns das nicht an Im Quellcode müssen wir die entsprechende bin_num in ZEND_MM_BINS_INFO

    • finden. Aus ZEND_MM_BINS_INFO wissen wir, dass die folgenden 4 Gruppen hinzugefügt werden, nämlich

    2^4, 2^5, 2^6...
    • Mit diesen Gruppierungsinformationen müssen wir die entsprechende Siez finden. Die bin_num

      • findet heraus, zu welcher Gruppe diese Größe gehört

      • und wie groß ist der Größenversatz innerhalb der Gruppe

      • Berechnen Sie die Ausgangsposition der Gruppe

    • Jetzt wird das Problem in die oben genannten 3 kleinen Probleme umgewandelt, wir werden sie einzeln lösen

    Finden Sie heraus, zu welcher Gruppe die Größe gehört
    • Der einfachste Weg ist, die Größen zu vergleichen, oder? Sie können if...else verwenden, um eine nach der anderen zu vergleichen, aber offensichtlich funktioniert PHP-Quellcode nicht so. Welche anderen Methoden haben wir also?

    • Wir können nichts Interessantes im Dezimalformat erkennen, also wandeln wir diese Werte in Binärwerte um und schauen uns das an

    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
    
    .....
    • Wenn wir uns die Binärzahlen oben ansehen, werden wir feststellen, dass die Längen der Binärzahlen in jeder Gruppe gleich sind und jede der folgenden eine Ziffer mehr als die vorherige hat

    • Das heißt, wir können die Länge der Binärzahl bestimmen. Wie lang ist das Binärsystem tatsächlich? Binärsystem ist 1

    • Dann wird das Problem in die Suche nach dem höchsten Wert im Binärsystem umgewandelt. Die Anzahl der Ziffern von 1

    • Die Lösung des PHP-Quellcodes wird hier vorerst nicht analysiert. Wir wissen nur, dass er das höchste Bit von

      in Binärform zurückgibt 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;

    Angenommen, die Größe, die wir beantragen, ist 65, dann gibt n hier 7 zurück
    • Berechnen Sie die Größe in der Gruppe. Der Versatz innerhalb von
    ist einfach. Subtrahieren Sie einfach die anfängliche Siezgröße jeder Gruppe von der Größe und dividieren Sie sie dann durch die Differenz in der aktuellen Gruppe (16, 32, 64...), also
    • (size-64)/16 (size-128)/32 (size-256)/64

      Schauen wir uns nun den im vorherigen Schritt zurückgegebenen Wert an. Jede Gruppe ist
    • , also schauen wir uns jetzt an, wie der Versatz innerhalb der berechnet wird Gruppe
    • 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

    Können wir
      von
    • subtrahieren, um

      zu erhalten, damit wir die Differenz der aktuellen Gruppe erhalten können (16, 32, 64...) basierend auf der Information, zu welcher Gruppe es gehört. 7、8、934、5、6

      Wenn die Größe 65 ist, ist der Versatz gleich
    • (64-64) / 2^4 = 0

      Berechnen Sie die Startposition der Gruppe
    Jetzt haben wir die Offset-Informationen, vorausgesetzt, unsere Gruppierung ist 1, 2, 3
    • Bedeutet das, dass wir
    • von der höchsten Ziffer von
    • subtrahieren müssen, um die Gruppierungsinformationen zu erhalten?

      16

      , um die Gruppierungsinformationen zu erhalten Gruppe?
    • Wir wissen, dass die Startposition
    • ist, was auch eine arithmetische Folge ist, die
    • 8、12、16... 4n+4

      Wir ist Schauen Sie sich das Beispiel der Größe = 65 an
      • 计算的偏移量是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> <pre class="brush:php;toolbar:false">binnum = (4n + 4) + (size / 2^n - 4) binnum = 4n + size / 2^n</pre> <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
    • 那么这行就好理解了,就是计算每组的起始位置4n对吧,左移两位就是乘以4

    第六行

    • return (int)(t1 + t2);

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

    Das obige ist der detaillierte Inhalt vonBerechnung kleiner Speicherspezifikationen in PHP (Codebeispiel). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen