【问题标题】:Free memory from file handler in PHP从 PHP 中的文件处理程序释放内存
【发布时间】:2015-03-11 01:18:00
【问题描述】:

最近我开始面对 PHP 中的内存管理问题。这对我来说是新事物,因为我不需要在后台线程上长时间运行 PHP 脚本。因此,现在我正在研究该主题并得出以下简单脚本:

function w()
{
    $f = fopen('test1.txt', 'w+');
    fclose($f);
    unset($f);
}

$i = 0;
$max = 5;

echo 'Memory usage:<br><br>';
echo $i . ' - ' . memory_get_usage() . '<br>';
touch('test1.txt');

while(++$i < $max)
{
    w();
    echo $i . ' - ' . memory_get_usage() . '<br>';
}

它只会多次打开和关闭同一个文件,每次关闭后都会显示使用的内存。

如您所见,即使在关闭和取消设置处理程序之后,内存也不会下降。似乎在内部指针仍在保存内存。我知道,它们只有几个字节,但如果脚本在后台线程上运行,即使是几个字节也会破坏脚本(这是我的真正目的)。

我尝试设置 $f = null 但它会消耗更多内存(我没疯,请自己检查)!而且 gc_collect_cycles() 也不起作用。

所以我的问题是:有没有办法完全释放文件处理程序的内存?

【问题讨论】:

  • 我只是重试了上面的脚本,没有改变内存。它第一次改变,然后在 261 次之后,然后保持静止,最多 5000 个循环。
  • 是的,我也注意到了这一点,但在实际情况下,每次运行时我都会打开许多​​文件。因此,内存使用量会增长,直到脚本中断。对我来说奇怪的是,即使关闭处理程序,内存也不会下降。
  • 您可能没有看到内存下降,因为 PHP 是垃圾收集器,并且垃圾收集器仅在您有空闲 CPU 时间(例如,如果您调用 sleep())或内存不足时运行- 以先到者为准。由于您没有内存不足并且没有让 CPU 休息一下,因此垃圾收集器没有运行,因此您没有释放内存。

标签: php file memory fopen fclose


【解决方案1】:

你可以fork到一个子进程,让子进程打开文件。

这样,当子进程结束时,它的所有资源都会被 PHP 垃圾收集进程清除。

Keep in mind, however that the child will have access to any resource created by the parent and he will also close them when he finishes.

更新帖子:

实际上,在通过命令行尝试了您的脚本之后(我只是将其修改为迭代 100 次而不是 5 次),这就是我得到的:

Memory usage:
0 - 119384
1 - 119564
2 - 119564
3 - 119564
4 - 119564
5 - 119564
6 - 119564
7 - 119564
8 - 119564
9 - 119564
10 - 119564
11 - 119564
12 - 119564
13 - 119564
14 - 119564
15 - 119564
16 - 119564
17 - 119564
18 - 119564
19 - 119564
20 - 119564
21 - 119564
22 - 119564
23 - 119564
24 - 119564
25 - 119564
26 - 119564
27 - 119564
28 - 119564
29 - 119564
30 - 119564
31 - 119564
32 - 119564
33 - 119564
34 - 119564
35 - 119564
36 - 119564
37 - 119564
38 - 119564
39 - 119564
40 - 119564
41 - 119564
42 - 119564
43 - 119564
44 - 119564
45 - 119564
46 - 119564
47 - 119564
48 - 119564
49 - 119564
50 - 119564
51 - 119564
52 - 119564
53 - 119564
54 - 119564
55 - 119564
56 - 119564
57 - 119564
58 - 119564
59 - 119564
60 - 119564
61 - 119564
62 - 119564
63 - 119564
64 - 119564
65 - 119564
66 - 119564
67 - 119564
68 - 119564
69 - 119564
70 - 119564
71 - 119564
72 - 119564
73 - 119564
74 - 119564
75 - 119564
76 - 119564
77 - 119564
78 - 119564
79 - 119564
80 - 119564
81 - 119564
82 - 119564
83 - 119564
84 - 119564
85 - 119564
86 - 119564
87 - 119564
88 - 119564
89 - 119564
90 - 119564
91 - 119564
92 - 119564
93 - 119564
94 - 119564
95 - 119564
96 - 119564
97 - 119564
98 - 119564
99 - 119564

【讨论】:

  • 嗯,这目前不是一个选项,因为在我的实际应用程序中,我做了几个文件操作,我不能仅仅为了完成这项工作而打开子进程。我最终会创建很多线程。除此之外,我想要一些我什至可以在共享虚拟主机上使用的东西,而且我们知道其中许多对系统资源的限制非常严格。
  • 但说实话@alfallouji,我已经在这样做了。为了让主线程运行更长的时间,我叫一个孩子来做主要的工作。但我还有一个内存泄漏问题需要解决。
【解决方案2】:

内存和文件句柄没有问题:它必须在脚本的其他位置。我运行了您的代码的以下版本(基本上创建了一个包含 5000 个 .jpg 文件的数组:清除迭代器使用的内存并仅将数组留在内存中。然后根据上面的脚本运行该文件列表。)

<?php

$i = 0;
$max = 5000;

$aFiles = array();

$it = new RecursiveDirectoryIterator("d:/");
foreach(new RecursiveIteratorIterator($it) as $file) {
    if (strcmp(substr($file, -4), '.jpg') == 0) {
        if ($i++ > $max) {
            break;
        }
        $aFiles[] = $file;
    }
}
unset($it);
unset($max);

gc_collect_cycles();

$i = 0;
echo 'Memory usage:<br><br>';
echo $i . ' - ' . number_format(memory_get_usage()) . '<br>';

foreach($aFiles as $file) {
    $f = fopen($file, 'r');
    fclose($f);
    unset($f);
    echo ++$i . ' - ' . number_format(memory_get_usage()) . '<br>';
    flush(); // Trying to ensure that the output buffer doesn't add to memory
}

?>

以下是(截断的)结果:

Memory usage:

0 - 3,553,000
1 - 3,552,608
2 - 3,552,728
3 - 3,552,728
4 - 3,552,728
5 - 3,552,728
.....
4997 - 3,552,728
4998 - 3,552,728
4999 - 3,552,728
5000 - 3,552,728
5001 - 3,552,728

结论:问题出在其他地方。示例:没有flush(),在输出大约 1K 后内存会增加,因为它会为输出缓冲区增加一个但更多。您能否确保没有其他原因导致内存处于打开状态,例如您是否正在递归调用 open 函数,每次都会添加到堆栈跟踪中?

【讨论】:

    猜你喜欢
    • 2012-02-19
    • 2014-03-21
    • 1970-01-01
    • 1970-01-01
    • 2021-01-11
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    • 2018-07-18
    相关资源
    最近更新 更多