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

Pav*_*rba 5 php arrays memory-management

我在array()和之间做了一些基准测试SplFixedArray(),我遇到了奇怪的行为.首先,看看我的简单测试(它实际上只是来自互联网的编辑版本,抱歉,我现在找不到原始资源):

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);
} 
Run Code Online (Sandbox Code Playgroud)

结果有点预期 - SplFixedArray()写作速度更快,阅读速度稍慢.当我在前一个SplFixedArray()测试之后放置另一个相同的测试时,事情开始变得奇怪unset(),请参阅输出:

> 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
Run Code Online (Sandbox Code Playgroud)

为什么第二次测试使用的内存少于第一次?嘿,我尝试添加下一个测试,并:

> 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
Run Code Online (Sandbox Code Playgroud)

所以我当然会尝试添加越来越多的内容,然后在512 kB之后再减少几次.我的问题在这里是显而易见的:如何可能以及为什么当我取消设置上一个对象并创建新对象时,使用的内存较低?它也可以正常工作array().

bwo*_*ebi 2

如果我们想理解这一点,我们需要进入引擎。更好:在Zend/zend_alloc.c (Zend 内存管理器)内部。

\n\n

内存管理器分配的内存被分成256 KB的块。

\n\n

释放 SPLFixedArray 时,仅释放第一个连续的内存块。始终保留一个 256 KB 的块(一些变量),然后进行累积。(其工作原理是操作系统分配的下一个内存将与该内存块相邻)

\n\n

然后,该内存段被标记为空闲,并在可能的情况下在下次使用,而不是从操作系统分配新内存。(如果需要的话,会附加一些内存)

\n\n

但由于至少有一个 256 KB 的块总是被释放,所以我们总是会注意到 256 KB 的差异。

\n\n
\n\n

当你想测量内存使用情况时,我真的会使用它memory_get_usage(false),因为它指示你 PHP (\xe2\x89\xa0 Zend) 需要多少内存。(唯一对memory_limitini 设置起作用的东西)

\n