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.
SieheZEND_MM_BINS_INFO
Dieses 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
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);
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
/* 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
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
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;
(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
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、9
3
4、5、6
(64-64) / 2^4 = 0
1
6
8、12、16...
4n+4
计算的偏移量是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
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">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</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
那么这行就好理解了,就是计算每组的起始位置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!