【问题标题】:PHP unset causes memory exhaustionPHP未设置导致内存耗尽
【发布时间】:2019-05-16 18:27:35
【问题描述】:

在我的脚本中,我想清除数组元素以从不再使用的数据中释放内存。

我发现自己处于使用 unset() 导致的奇怪情况:

( ! ) 致命错误:允许的内存大小为 134217728 字节已用尽 (试图分配 16777224 字节)在 .../models/Persons.php 第 60 行

这是导致此问题的代码部分:

$chunks_count = count($this->xml_records_chunk['fnames']) - 1;
for ($num = 0; $num <= $chunks_count; $num++) {
      $chunks_count = count($this->xml_records_chunk['fnames']) - 1;

       $not_last = ($num < $chunks_count ? ',' : '');

       $new_records .= '(' . $this->xml_records_chunk['fnames'][$chunks_count] . ','
        . $this->xml_records_chunk['lnames'][$chunks_count] . ' , '
        . $this->xml_records_chunk['dobs'][$chunks_count] . ' , '
        . $this->xml_records_chunk['phones'][$chunks_count] . ' )' . $not_last;
       unset($this->xml_records_chunk['fnames'][$chunks_count]);
       unset($this->xml_records_chunk['lnames'][$chunks_count]);
       unset($this->xml_records_chunk['dobs'][$chunks_count]);
       unset($this->xml_records_chunk['phones'][$chunks_count]);
}

脚本可以正常工作而无需取消设置。

现在的问题是:

  • 为什么未设置会导致内存耗尽?
  • 在这种情况下,取消设置未使用的数组元素的正确方法是什么?

我已经检查过这个例子:

Ok null 确实以其他方式工作,因为脚本在第 61 行 - 第 3 行未设置时死亡。

【问题讨论】:

  • $this-&gt;xml_records_chunk['fnames'] 是数组还是实现类数组方法的对象?
  • 您可能希望使用XMLReaderXML Parser 来处理XML,而不是将整个文件加载到内存中。
  • 我正在使用 XMLReader。 $this-&gt;xml_records_chunk 是一个数组。
  • 我无法发布解决方案,因为这并没有解决,但是我在这里遇到的问题是误解了 unset 如何与垃圾收集一起工作。一般来说,我认为可能存在一些 php 错误。我不得不处理大约 100 万个元素的数组,并且出现了奇怪的情况。我试图控制内存使用(吸取了教训 - 不值得),所以在 200.000 个元素之后有 70mb 的使用量。但是在 200.001 上突然 140mb,此时内存使用量已超出但 php 仍向未设置的块移动。

标签: php memory unset


【解决方案1】:

这是一个很好的问题,为什么你的 unset 会破坏你的记忆。但是您在代码中将$this-&gt;xml_records_chunk 称为变量。所以我建议你有一个包含所有现有元素的数组,这样你就已经分配了完整的内存。

我认为在这种情况下,您不需要清理数组和内存,因为您已经分配了该内存。 GC没那么糟糕。因此,如果您的脚本不再使用该变量,它就会被清除。

在您的情况下,我建议您更改数组结构并将迭代器放在值的第一个条目中,如下所示:

$this->xml_records_chunk[$chunks_count]['phones']

那么你有以下结构

$this->xml_records_chunk[$chunks_count] = [
    'phones',
    '...',
    '...
]

然后您可以使用

清除单个未设置的完整数组

unset($this-&gt;xml_records_chunk[$chunks_count])

这可能会减少问题,也许您可​​以检查Iterator-Interface 以迭代和删除您的数据。

【讨论】:

  • 我明白了你的观点,但我认为我会保留我的结构,因为我在很多地方都使用它。好吧,我们都知道这只是很小的变化,但它可能会导致一些额外的错误。顺便提一句。当我调试当前代码时, unset 工作正常 - 我的意思是,数组 0f ~240 000 个元素缩小到 239 999,所以它可以工作。 Unset 本身会删除该变量。但我想我知道此时可能导致问题的原因 - 稍后将对其进行测试,并将检查迭代器接口。
  • 好的,所以我认为分配$new_records 已经破坏了内存,但事实并非如此。只留下未设置会破坏第二次未设置的记忆。也许您知道我是否可以使用 xdebug + phpStorm 检查给定位置使用了多少内存?还是类似 Htop for linux 之类的?
  • 我发现了这个 xdebug_profilerkcache 并且我已经看到了内存泄漏 - 也许有问题。
猜你喜欢
  • 1970-01-01
  • 2023-03-05
  • 2011-05-06
  • 2015-07-02
  • 2012-12-09
  • 1970-01-01
  • 2015-10-01
  • 1970-01-01
相关资源
最近更新 更多