【问题标题】:PHP, mysql memory leakPHP、mysql内存泄漏
【发布时间】:2023-03-17 12:06:01
【问题描述】:

面对一个问题,我在使用数据库时找不到内存泄漏。该脚本从数据库中获取大量数据,因此内存泄漏至关重要。使用 mysqli、mysql 或 PDO 时会出现此问题。 这是测试代码:

$link = mysqli_connect('localhost', 'root', '');
if (!$link) {
    die('Connection error: ' . mysql_error());
}
mysqli_select_db($link, 'coolstat.my') or die ('Can\'t use coolstat.my: ' . mysql_error());


for($ii=0; $ii<20000; $ii+=1000){
    $sql= "SELECT `codes_data`.* FROM `codes_data` INNER JOIN codes ON codes.siteid= 20     AND codes.codeid=codes_data.codeid LIMIT ".$ii.", ".($ii+1000)."";
    ///

    $data= array();
    $result = mysqli_query($link, $sql);
    while (($row = mysqli_fetch_array($result))){
        $data[]= $row;
    }
    mysqli_free_result($result);
    unset($result);
    unset($data);
    echo "Memory get_data usage: ".convert_memory_val(memory_get_peak_usage(true))."<br />\n";
}
mysqli_close($link);


function convert_memory_val($size){
    $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
    return @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $unit[$i];
}

它输出:

Memory get_data usage: 3.25 mb
Memory get_data usage: 6 mb
Memory get_data usage: 9 mb
Memory get_data usage: 11.75 mb
Memory get_data usage: 14.75 mb
Memory get_data usage: 17.75 mb
Memory get_data usage: 20.5 mb
Memory get_data usage: 23.5 mb
Memory get_data usage: 26.5 mb
Memory get_data usage: 29.5 mb
Memory get_data usage: 32.25 mb
Memory get_data usage: 35.25 mb
Memory get_data usage: 38.25 mb
Memory get_data usage: 41.25 mb
Memory get_data usage: 44 mb
Memory get_data usage: 47 mb
Memory get_data usage: 50 mb
Memory get_data usage: 53 mb
Memory get_data usage: 56 mb
Memory get_data usage: 58.75 mb

【问题讨论】:

  • 不是主题,但你需要用 mysqli_error($link) 替换 mysql_error。
  • 您无法控制 PHP 如何进行垃圾收集。您不能以这种方式测量“内存泄漏”!见:php.net/manual/en/features.gc.php
  • 这真的是评论,而不是答案。你不是新手,你应该已经知道评论和答案的区别了。
  • 不是生产脚本,只是快速复制粘贴
  • 但是我可以加速这个,还是手动清理内存?

标签: php mysql memory-leaks pdo mysqli


【解决方案1】:

你的错误在于限制子句:第二个数字应该是一个常数,例如。 1000. 你有什么查询将是

LIMIT 0, 1000
LIMIT 1000, 2000
LIMIT 2000, 3000
...

这不是分页,您以越来越多的重叠块获取数据。所以增加内存使用是正确的。

【讨论】:

  • 谢谢,你拯救了我的一天!
【解决方案2】:

garbage collector 开启时,只要根缓冲区满了,就会执行上述循环查找算法。根缓冲区的固定大小为 10,000 个可能的根 [...]

即使可能的根缓冲区尚未满,也可以强制收集循环。为此,您可以使用gc_collect_cycles() 函数。此函数将返回算法收集了多少个周期。

所以 .. 尝试在循环体的末尾force garbage collection

for ($ii = 0; $ii < 20000; $ii += 1000) {
    // ...

    mysqli_free_result($result);
    unset($result);
    unset($data);
    echo "Memory before GC run: ".convert_memory_val(memory_get_peak_usage(true))."<br />\n";

    $n = gc_collect_cycles();
    echo "GC collected $n garbage cycles<br />\n";
    echo "Memory after GC run: ".convert_memory_val(memory_get_peak_usage(true))."<br />\n";
}

【讨论】:

  • @ВладФедосов .. 这就是您在长时间运行的脚本中手动释放内存的方式。答案可能有助于其他人学习。
猜你喜欢
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
  • 2016-02-10
  • 2012-04-17
  • 2012-01-12
  • 2017-01-28
  • 2016-03-30
  • 1970-01-01
相关资源
最近更新 更多