Недавно я начал сталкиваться с проблемами управления памятью в 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>';
}
Он только открывает и закрывает один и тот же файл несколько раз, а после каждого закрытия отображает используемую память.
Как видите, даже после закрытия и unset () обработчика, память не падает. Кажется, что внутренне указатель все еще держит память. Я знаю, что это несколько байтов, но даже несколько байтов могут сломать скрипт, если он выполняется в фоновом потоке (это моя настоящая цель).
Я попытался установить $ f = null, но он потребляет еще больше памяти (я не сумасшедший, проверьте сами)! И gc_collect_cycles () также не работал.
Итак, мой вопрос: есть ли способ полностью освободить память обработчика файлов?
Вы можете перейти к дочернему процессу и позволить дочернему процессу открыть файл.
Таким образом, когда дочерний процесс завершится, все его ресурсы будут очищены процессом сборки мусора в 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
Нет проблем с памятью и дескрипторами файлов: это должно быть в другом месте вашего скрипта. Я запустил следующую версию вашего кода (в основном создает массив 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()
память увеличивается примерно после 1 Кбайт вывода, так как добавляет еще больше для буфера вывода. Можете ли вы убедиться, что ничто другое не учитывает открытость памяти, например, Вы вызываете рекурсивную функцию open, которая будет добавлять к трассировке стека каждый раз?