Очистить память, используемую PHP


Я столкнулся с интересной проблемой. Я использую PHPUnit, и мои тесты занимают больше памяти каждый раз, когда я их запускаю. Т.е....

2,25 МБ

2,5 МБ

3,0 МБ

3,5 МБ .......

Кто-нибудь знает, как очистить потребляемую память, и может ли кто-нибудь посоветовать мне подробно изучить это? Непосредственная проблема заключается в том, что у некоторых из моих более крупных тестов заканчивается память, и они просто продолжают увеличивать максимальное выделение памяти в PHP недостаточно хорош...Мне нужно знать, почему тест PHPUnit, выполняемый из командной строки, будет использовать память, которая "зависает" между запусками.

Author: Calvin Froedge, 2012-11-24

4 answers

Кельвин, как обсуждалось в чате , это произошло из-за отсутствия функций сброса.

При тестировании мы должны убедиться, что среда тестирования согласована, чтобы мы могли получать точные результаты. Вычисления - это ввод/вывод, и поэтому мы должны использовать Приспособления в PHPUnit для сброса хранилища, чтобы предотвратить подобные "утечки памяти".

 5
Author: mauris, 2012-11-24 02:15:29

Увеличение объема памяти имеет три-четыре причины:

1) PHPUnit собирает данные о покрытии кода

Вы ничего не можете с этим поделать, кроме как отключить покрытие кода.

2) PHPUnit кэширует маркеры файлов для покрытия кода

Вы можете использовать <phpunit cacheTokens="false"> в своем xml-файле PHPUnit. Смотрите заметку об этом в http://phpunit.de/manual/current/en/installation.html#installing.upgrading

3) PHPUnit не убирает должным образом после того, как он сам

В нем текущая реализация сохраняет тестовые случаи, потому что именно там хранятся данные о результатах. В будущем это будет изменено, чтобы быть более эффективным, но пока все работает именно так.

4) Ведущий к "4": Вам тоже нужно убирать за собой

Поскольку экземпляры TestCase хранятся рядом с вашими переменными-членами, они также хранятся рядом.

Это означает, что вы можете сэкономить много памяти, используя

public function tearDown() {
    unset($this->whatever);
}

Но делать это очень утомительно.

Мой предлагаю создать базовый тестовый класс для всех ваших тестовых наборов и использовать его:

class MyBaseTest extends \PHPUnit_Framework_TestCase {

    protected function tearDown()
    {
        $refl = new \ReflectionObject($this);
        foreach ($refl->getProperties() as $prop) {
            if (!$prop->isStatic() && 0 !== strpos($prop->getDeclaringClass()->getName(), 'PHPUnit_')) {
                $prop->setAccessible(true);
                $prop->setValue($this, null);
            }
        }
    }
}

Это приведет к очистке после вас приятным автоматизированным способом.

(реквизиты для фрагмента идут по адресу: http://kriswallsmith.net/post/18029585104/faster-phpunit)


PHPUnit не может сделать это обратно сопоставимым способом, который не нарушил бы проекты людей, поэтому вы должны добавить его для себя:)

 23
Author: edorian, 2014-04-07 13:52:00

Технические детали сборки мусора PHPUnit уже были рассмотрены @edorian и @mauris, но я хотел добавить, что PHPUnit (по крайней мере, в версии 3.7.21, которую я запускаю) дает вам возможность добавить комментарий:

/**
 * @backupGlobals disabled
 */
class MyClassTests extends PHPUnit_Framework_TestCase{}

Перед добавлением аннотации я примерно удваивал объем используемой памяти при каждом запуске моего набора тестов, последний из которых составлял около 1100 МБ. Теперь они работают на 15 Мбайт.

 4
Author: ktrots, 2013-12-23 17:02:53

Если вы используете PDO (или аналогичную абстракцию базы данных), то вы можете использовать "sqlite::память:" в качестве DSN. Это имеет три больших преимущества:

  1. Автоматическая очистка после каждого теста
  2. Нет возможности случайно коснуться производственной базы данных (например, даже при запуске модульных тестов на рабочем сервере).
  3. Все в памяти, поэтому тесты могут выполняться быстрее

Недостатком является то, что ваш SQL должен быть переносимым между MySQL и SQLite. Это может оказаться будет довольно много работы (для больших проектов это часто того стоит, не только для тестов, но и для того, как это улучшит дизайн вашего кода). В вашем случае вы упоминаете об использовании доктрины в стенограмме чата, так что у вас уже может быть хорошая абстракция, и поэтому она может просто работать без изменений на SQLite.

 1
Author: Darren Cook, 2012-11-25 00:32:23