@MuTaToRage

Как отучить php сжирать память?

Здравствуйте, появилась задача написать парсер который будет очень долго работать. И работать он будет с массивами объектов добавляя и удаляя их.
Так вот, обнаружил я что в разное время он падает от пересжирания памяти, и решил я изучить вопрос.
Написал тестовый код, который сказал мне что я не разбираюсь в php.
<?php

$start = 0;
$start = memory_get_usage();
print 'start script:'.number_format(memory_get_usage()-$start)."\r\n";
class A{}
print 'declare class:'.number_format(memory_get_usage()-$start)."\r\n";


$arrayTest = [];
print 'create array:'.number_format(memory_get_usage()-$start)."\r\n";
for($i=0;$i<100000;$i++)
{
    $arrayTest[] = new A;
}
print 'insert Object to array:'.number_format(memory_get_usage()-$start)."\r\n";

for($i=0;$i<100000;$i++)
{
    unset($arrayTest[$i]);
}
print 'usnet elements of array:'.number_format(memory_get_usage()-$start)."\r\n";

unset($arrayTest);
print 'usnet array:'.number_format(memory_get_usage()-$start)."\r\n";

Вроде всё достаточно наглядно. память выделили, освободили. Всё должно прийти в ноль.
Но результат вышел совсем не такой какой я себе ожидал.

start script:0
declare class:88
create array:224
insert Object to array:15,086,176
usnet elements of array:4,686,136
usnet array:4,161,704

Изначально я подумал что проблема в работе с массивом. Но заменив объект на число результат такой

start script:0
create array:224
insert integer to array:8,524,656
usnet elements of array:524,600
usnet array:168

Кто знает как с этим бороться?
  • Вопрос задан
  • 691 просмотр
Решения вопроса 1
@zano3adev
Web Dev
Фича PHP:
php.net/manual/ru/features.gc.refcounting-basics.p...

Решения:
1. Вместо объекта использовать массив.
2. Сериализация/Десериализация объекта.
class TestMemory
{
    protected $memory_start;
    protected $memory_filled_array;
    protected $memory_empty_array;
    protected $memory_deleted_array;

    protected $array;

    public function __construct()
    {
        $this->memory_start = 0;
        $this->memory_filled_array = 0;
        $this->memory_empty_array = 0;
        $this->memory_deleted_array = 0;
    }

    public function runTest()
    {
        $this->memory_start = memory_get_usage();
        $this->array = [];
        for($i = 0; $i < 10000; $i++)
        {
            $object = new stdClass();
            $object->property1 = $i;
            $object->property2 = 123;
            $object->property3 = str_repeat('Str', 100);

            $this->array[] = serialize($object);
            unset($object);
        }
        $this->memory_filled_array = memory_get_usage();
        for($i = 0; $i < 10000; $i++)
        {
            $object = unserialize($this->array[$i]);
            //$object; //do some
            unset($this->array[$i], $object);
        }
        $this->memory_empty_array = memory_get_usage();
        unset($this->array, $i);
        $this->memory_deleted_array = memory_get_usage();
    }

    public function printResult()
    {
        $result = '---Result---' . '<br>';
        foreach($this as $name => $value)
        {
            if($name !== 'array')   $result .= $name . ': ' . number_format($value / 1024 / 1024, 2) . 'MB.' . '<br>';
        }
        $result .= 'Memory leak: ' . ($this->memory_deleted_array - $this->memory_start) . 'Byte' . '<br>';
        echo $result;
    }
}

$test = new TestMemory();
for($i = 0; $i < 5; $i++)
{
    $test->runTest();
    $test->printResult();
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
kpa6uu
@kpa6uu
Программист Талибана [Пыхерский Алибаба]
unset не очищает память, он лишь удаляет переменную.
Затестите тот же код, но в этот раз замените unset на = null;
Ответ написан
index0h
@index0h
PHP, Golang. https://github.com/index0h
unset не очищает память, этим занимается чистильщик мусора, можете вручную запустить php.net/manual/ru/function.gc-collect-cycles.php
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы