Memory Usage Things you need to know about memory usage and management

Introduction

The SetaPDF components make heavy use of passing objects to other objects for observing or other purposes which ends in cycled references between the objects.

By doing this there are cycled references created which has to be collected by the garbage collection logic of PHP.

Common Memory Management

To allow the Garbage Collection to clean up the cycled references it is a requirement that no variable points to the related object in a specific variable scope.

To gain the full benefit of the Garbage Collection it is a prefered way to encapsulate memory intensive task into method/function scope. This way the Garbage Collection can clean up the references when the scope is left and it is not needed to unset the variables manually.

Following PHP code shows the behavior:

PHP
<?php

use setasign\SetaPDF2\Core\Document;
use setasign\SetaPDF2\Core\PageFormats;

require_once('library/SetaPDF/Autoload.php');

function createPdfInSeparateScope()
{
    $document = new Document();
    $catalog = $document->getCatalog();
    $pages = $catalog->getPages();
    $tmpPages = [];
    for ($i = 200; $i > 0; $i--) {
        $tmpPages[] = $pages->create(PageFormats::A4);
    }
}

echo 'First of all we create the variables in the function scope: <br />';
createPdfInSeparateScope();
echo 'Memory usage afterwards is: ' . memory_get_usage() . '<br />' .
     'The memory consumption is increased and cycles are not collected, ' .
     'because the possible root buffer is not full yet.<br />';

$cycles = gc_collect_cycles();
echo $cycles . ' were collected.<br />' .
     'Memory usage afterwards: ' . memory_get_usage() . '<br />';

echo '<br />';
echo 'Now we create the same variables in the global scope. And we try to ' .
     'collect the cycles without unsetting the variables:<br />';

$document = new Document();
// let's create some memory usage
$catalog = $document->getCatalog();
$pages = $catalog->getPages();
$tmpPages = array();
for ($i = 200; $i > 0; $i--) {
    $tmpPages[] = $pages->create(PageFormats::A4);
}

$cycles = gc_collect_cycles();
echo $cycles . ' were collected.<br />';
echo 'Memory usage afterwards: ' . memory_get_usage() . '<br />';

echo '<br />';
echo 'Now we unset the variables and try to collect the cycles again:<br />';
unset($document, $catalog, $pages, $tmpPages);

$cycles = gc_collect_cycles();
echo $cycles . ' were collected.<br />';
echo 'Memory usage afterwards: ' .  memory_get_usage() . '<br />';

By default, PHP's garbage collector is turned on. There is, however, a php.ini setting that allows you to change this: zend.enable_gc.

More information about PHP's garbade collector and how to control its behavior can be found here.