Очистить память, используемую PHP
У меня возникает интересная проблема. Я использую PHPUnit, и мои тесты занимают больше памяти каждый раз, когда я их запускаю. Т.е....
2,25 МБ
2,5 МБ
3,0 МБ
3,5 МБ
.......
Кто-нибудь знает, как очистить память, которая потребляется, и может ли кто-нибудь посоветовать мне изучить это подробно? Непосредственная проблема заключается в том, что некоторые из моих более крупных тестов заканчиваются из памяти, и просто продолжая увеличивать максимальный объем выделения памяти в PHP, недостаточно. Мне нужно знать, почему тест PHPUnit, запущенный из командной строки, будет иметь память использование, которое "прилипает" между прогонами.
Ответы
Ответ 1
Calvin, как обсуждалось в chat, из-за отсутствия функций reset.
При тестировании мы должны убедиться, что тестовая среда согласована, чтобы мы могли получать точные результаты. Computing - Input/Output, поэтому мы должны использовать Fixtures в PHPUnit для хранилища reset для предотвращения утечек памяти.
Ответ 2
Увеличение памяти имеет три-четыре причины:
1) PHPUnit собирает данные о покрытии кода
С этим ничего не поделаешь, кроме отключения кода.
2) PHPUnit кэширует файловые токены для покрытия кода
Вы можете использовать <phpunit cacheTokens="false">
в своем PHPUnit xml. См. Примечание об этом в http://phpunit.de/manual/current/en/installation.html#install.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 не может сделать это обратно совместимым способом, который не нарушил бы проекты людей, поэтому вы должны добавить его для себя :)
Ответ 3
Технические подробности сборки мусора PHPUnit уже были покрыты @edorian и @mauris, но я хотел добавить, что PHPUnit (по крайней мере, в версии 3.7.21, который я запускаю) дает вам возможность добавлять комментарий:
/**
* @backupGlobals disabled
*/
class MyClassTests extends PHPUnit_Framework_TestCase{}
Прежде чем добавлять аннотацию, я примерно удвоил использование своей памяти в каждом прогоне моего тестового набора, последний из которых достиг 1100 МБ. Теперь они работают на 15 МБ.
Ответ 4
Если вы используете PDO (или аналогичную абстракцию базы данных), вы можете использовать "sqlite:: memory:" как вы DSN. Это имеет три больших преимущества:
- Автоматическая очистка после каждого теста
- Невозможно случайно коснуться производственной базы данных (например, даже при выполнении модульных тестов на вашем производственном сервере).
- Все в памяти, поэтому тесты могут работать быстрее
Недостаток заключается в том, что ваш SQL должен быть переносимым между MySQL и SQLite. Это может оказаться довольно большой работой (для больших проектов это часто стоит не только для тестов, но и для того, как это улучшит ваш дизайн кода.) В вашем случае упоминание использования Doctrine в стенограмме чата, поэтому у вас может быть хорошая абстракция, и поэтому она может запускаться без изменений в SQLite.