Segfault bei PHPUnit vermeiden

Wir führen unsere Unittests automatisiert beim Push auf das Git-Repository mit Jenkins aus. Bevor Änderungen auf dem Livesystem eingespielt werden dürfen ist ein “grüner Build” zwingend erforderlich. Bei größeren Projekten kam es bei der Ausführung von PHPUnit immer wieder zu Segmentation Faults mit exec returned: 139. Beim zweiten Anlauf funktionierte es dann meistens, aber es ist natürlich sehr lästig, weil dadurch bei einer Dauer von ca. 30 Minuten für einen vollständigen Build das Livestellen unnötig verzögert wird.

Im Netz kursieren teils abenteuerliche Lösungen, die beispielsweise den automatischen Neustart von PHPUnit bei einem Segfault favourisieren. Klar, das ist besser als nichts, aber behebt das Problem nun mal nicht. Interessant fand ich daher den dritten Kommentar zu oben genanntem Artikel:

In phpunit you can do:
phpunit -d zend.enable_gc=0

Bei meinem ersten Versuch mit deaktivierter Garbage Collection wurde natürlich das memory_limit überschritten. Eine Erhöhung auf 1,5GB löste zwar das Problem mit dem Limit, jedoch brach daraufhin PHPUnit bei der Erzeugung des Clover-Reports unvermittelt ab. Diesmal mit exec returned: 143. Google förderte leider kaum brauchbare Ergebnisse zutage, jedoch lag die Vermutung nahe, dass es eben nicht so optimal ist, die Garbage Collection für den kompletten PHPUnit-Lauf zu deaktivieren.

Daraufhin haben wir eine eigene Zwischenklasse zwischen PHPUnit_Framework_TestCase und unsere TestCases geschoben, in der die Garbage Collection explizit gesteuert wird. Vor jedem Test wird die GC explizit mit gc_collect_cycles() aufgerufen, anschließend für den Test deaktiviert und nach dem Test wieder aktiviert:

<?php
abstract class Flagbit_Test_PHPUnit_TestCase extends PHPUnit_Framework_TestCase
{
    protected function setUp()
    {
        gc_collect_cycles();
        gc_disable();

        parent::setUp();
    }

    protected function tearDown()
    {
        parent::tearDown();

        gc_enable();
    }
}

Dies funktioniert jetzt seit einigen Tagen recht gut. Ob das Problem damit wirklich aus der Welt ist, wird sich in den nächsten Wochen zeigen!