简体   繁体   English

减少数组和SplFixedArray的内存使用量

[英]Decreasing memory usage for array and SplFixedArray

I was doing some benchmarks between array() and SplFixedArray() and I run into strange behaviour. 我在array()SplFixedArray()之间做了一些基准测试,我遇到了奇怪的行为。 At first, look at my simple test (it's actually just edited version from internet, sorry, I can't find original source now): 首先,看看我的简单测试(它实际上只是来自互联网的编辑版本,对不起,我现在找不到原始资料):

function formatMemoryUsage($usage) {
   $unit = array(' B', 'kB', 'MB', 'GB', 'TB');
   $factor = floor((strlen($usage) - 1) / 3);

   return sprintf('%.2f %s (%d bytes) ', $usage / pow(1024, $factor), $unit[$factor], $usage);
}

for($size = 1000; $size < 100000; $size *= 2) { 
   echo PHP_EOL . '> Testing size: ' . number_format($size) . PHP_EOL; 
   echo '   Array()' . PHP_EOL;

   for($s = microtime(true), $m = memory_get_usage(true), $container = Array(), $i = 0; $i < $size; $i++) $container[$i] = null; 
      echo '      - Write         - time   : ' . str_pad(microtime(true) - $s, 20, '0') . '     - memory: ' . formatMemoryUsage(memory_get_usage(true) - $m) . PHP_EOL; 

   $s = microtime(true); 
   foreach ($container as $key => $value) {
      $void = $value;
   }
   echo '      - Read          - time   : ' . str_pad(microtime(true) - $s, 20, '0') . PHP_EOL;

   unset($container);

   echo '   SplFixedArray()' . PHP_EOL;

   for($s = microtime(true), $m = memory_get_usage(true), $container = new SplFixedArray($size), $i = 0; $i < $size; $i++) $container[$i] = null; 
   echo '      - Write         - time   : ' . str_pad(microtime(true) - $s, 20, '0') . '     - memory: ' . formatMemoryUsage(memory_get_usage(true) - $m) . PHP_EOL; 

   $s = microtime(true); 
   foreach ($container as $key => $value) {
      $void = $value;
   }
   echo '      - Read          - time   : ' . str_pad(microtime(true) - $s, 20, '0') . PHP_EOL; 

   unset($container);
} 

Results were kind of expected - SplFixedArray() was faster in writing and little bit slower in reading. 结果有点预期 - SplFixedArray()写入速度更快,读取速度稍慢。 Things starts to be strange when I put another same SplFixedArray() test right after unset() of previous one, see the output: 当我在前一个的unset()之后放入另一个相同的SplFixedArray()测试时,事情开始变得奇怪,请参阅输出:

> Testing size: 64,000
   Array()
      - Write         - time   : 0.009041070938110400     - memory: 7.50 MB (7864320 bytes) 
      - Read          - time   : 0.004010915756225600
   SplFixedArray()
      - Write         - time   : 0.004639148712158200     - memory: 1.75 MB (1835008 bytes) 
      - Read          - time   : 0.005971908569335900
   SplFixedArray()
      - Write         - time   : 0.005653858184814500     - memory: 1.50 MB (1572864 bytes) 
      - Read          - time   : 0.006288051605224600

Why second test use less memory than first one? 为什么第二次测试使用的内存少于第一次? And hey, I try to add next test and: 嘿,我尝试添加下一个测试,并:

> Testing size: 64,000
   Array()
      - Write         - time   : 0.008963823318481400     - memory: 7.50 MB (7864320 bytes) 
      - Read          - time   : 0.004142045974731400
   SplFixedArray()
      - Write         - time   : 0.005026102066040000     - memory: 1.75 MB (1835008 bytes) 
      - Read          - time   : 0.005756139755249000
   SplFixedArray()
      - Write         - time   : 0.004483938217163100     - memory: 1.50 MB (1572864 bytes) 
      - Read          - time   : 0.005591869354248000
   SplFixedArray()
      - Write         - time   : 0.004633903503418000     - memory: 1.25 MB (1310720 bytes) 
      - Read          - time   : 0.005697011947631800

So I of course try to add more and more and after few more decreasing stoped on 512 kB . 所以我当然会尝试添加越来越多的内容,然后在512 kB之后再减少几次。 My question here is obvious: How it is possible and why that when I unset previous object and create new one, used memory is lower? 我的问题在这里是显而易见的: 如何可能以及为什么当我取消设置上一个对象并创建新对象时,使用的内存较低? And it works with normal array() too. 它也适用于普通的array()

We need to go into the engine if we want to understand this. 如果我们想了解这一点,我们需要进入引擎。 Better: inside of Zend/zend_alloc.c (The Zend Memory Manager) . 更好:在Zend / zend_alloc.c(Zend Memory Manager)中

The memory allocated by the memory manager is split into chunks of 256 KB . 内存管理器分配的内存被分成256 KB的块。

Upon freeing the SPLFixedArray, only the first contiguous chunk of memory is freed . 释放SPLFixedArray后, 释放第一个连续的内存块 There always remains a block of 256 KB (some variables) which then accumulates. 始终存在256 KB(某些变量)的块,然后累积。 (which works as the next from the OS allocated memory will be just adjacent to this memory block) (作为OS分配的内存的下一个工作将与此内存块相邻)

This memory segment is then marked as free and used the next time when possible instead of allocating new memory from the OS. 然后将此内存段标记为空闲,并在可能的情况下下次使用,而不是从OS分配新内存。 (and if necessary some memory is appended) (如果需要,还会附加一些内存)

But as at least one block of 256 KB is always freed, we always will notice a difference of 256 KB. 但由于至少有一个256 KB的块总是被释放,我们总会注意到256 KB的差异。


When you want to measure memory usage, I really would use memory_get_usage(false) as it indicates you how much memory PHP (≠ Zend) needs. 当你想测量内存使用量时,我真的会使用memory_get_usage(false)因为它表明PHP(≠Zend)需要多少内存。 (the only thing which counts against the memory_limit ini setting) (对memory_limit ini设置唯一重要的事情)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM