Aller au contenu

Performance : analyseur de fragmentation de la mémoire

Le module Performance reste volontairement compact. Il expose un seul outil purement observationnel — MemoryFragmentationAnalyzer — qui mesure le pic de mémoire et la mémoire retenue sur des fenêtres balisées du travail du moteur. Sa surface d’API comprend aussi l’instantané immuable produit par cet outil. Il n’impose aucun budget, ne limite rien et ne modifie pas le comportement du moteur.

Portée et stabilité. La vraie surface de ce module se résume à deux classes (MemoryFragmentationAnalyzer, MemoryFragmentationSnapshot). Ce n’est pas un mécanisme d’application de budget par opération. La valeur performance_budget présente dans le front-matter de chaque module est une convention de documentation, et non quelque chose que ce module impose. La surface est experimental : c’est un diagnostic introduit en @since 3.2.0. La forme de son instantané peut évoluer.

Fenêtre de terminal
composer require nextpdf/core:^3

L’utilisation des ressources est une exigence de qualité de premier ordre pour un moteur PDF. L’observable minimal qui la couvre distingue la mémoire de pic (le maximum atteint pendant une fenêtre) de la mémoire retenue (ce qui reste encore détenu après la fenêtre). Ce module mesure exactement cela, et rien de plus.

MemoryFragmentationAnalyzer est purement observationnel — il ne modifie ni l’état du writer ni celui du document. reset() exécute un cycle de GC et réinitialise le compteur de pic de PHP, de sorte que les mesures suivantes puissent être attribuées à la fenêtre ouverte depuis cette réinitialisation. mark(string $label) capture un MemoryFragmentationSnapshot à un point étiqueté. snapshots() renvoie la série capturée. peakDelta() et retainedDelta() rapportent la variation du pic et de la mémoire retenue sur l’ensemble de l’exécution.

MemoryFragmentationSnapshot est un objet-valeur final readonly : un point étiqueté qui expose transientBytes() (le pic moins la mémoire retenue — la mémoire utilisée puis libérée), retentionRatio() (la mémoire retenue rapportée au pic) et toArray() pour l’export. Une valeur élevée d’octets transitoires avec un faible ratio de rétention signale un brassage qu’une stratégie de réutilisation de tampon pourrait éliminer. Les deux classes sont @since 3.2.0.

ClasseMembres clésRôle
MemoryFragmentationAnalyzerreset(), mark(string $label), snapshots(), peakDelta(), retainedDelta()Analyseur de mémoire en observation seule (@since 3.2.0)
MemoryFragmentationSnapshottransientBytes(), retentionRatio(), toArray()Mesure étiquetée immuable (@since 3.2.0)

Lance composer docs:generate-api-php -- --module=Performance pour consulter la table PHPDoc complète.

Encadre un chemin d’exécution chaud et lis les deltas.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Performance\MemoryFragmentationAnalyzer;
$analyzer = new MemoryFragmentationAnalyzer();
$analyzer->reset();
$analyzer->mark('before-write');
// ... engine work under observation ...
$analyzer->mark('after-write');
printf("Peak delta: %d B, retained delta: %d B\n", $analyzer->peakDelta(), $analyzer->retainedDelta());

Encadre un rendu et envoie l’instantané de fragmentation vers un collecteur de métriques, en traitant un faible ratio de rétention associé à un volume élevé d’octets transitoires comme un signal de brassage.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Performance\MemoryFragmentationAnalyzer;
use Psr\Log\LoggerInterface;
final readonly class RenderMemoryProbe
{
public function __construct(private LoggerInterface $logger) {}
/** @param callable():void $render The render closure to observe. */
public function observe(callable $render): void
{
$analyzer = new MemoryFragmentationAnalyzer();
$analyzer->reset();
$analyzer->mark('start');
$render();
$analyzer->mark('end');
foreach ($analyzer->snapshots() as $snapshot) {
$this->logger->info('mem-frag', $snapshot->toArray());
}
}
}
  • reset() appelle gc_collect_cycles() et memory_reset_peak_usage(). Son effet sur le compteur de pic de PHP est global au processus. Ne l’utilise pas en alternance avec un autre composant qui lit aussi le compteur de pic dans la même requête.
  • Les mesures sont attribuables à la fenêtre ouverte depuis le dernier reset(). Un mark() sans reset() préalable mesure depuis le démarrage du processus, ce qui n’est généralement pas ce que tu veux.
  • C’est un diagnostic, pas un contrôle. Il ne limite jamais le travail et ne l’interrompt jamais ; ne construis pas de contre-pression à partir de ce signal.
  • Le profil de reproductibilité est structural : les chiffres en octets dépendent du runtime, de l’allocateur et de l’état du GC. Deux exécutions produisent des valeurs numériques différentes, même pour un même travail logique.

Le surcoût propre de l’analyseur tient à un cycle de GC sur reset() et à une lecture hrtime() / memory_get_* par mark() — négligeable au regard du travail qu’il observe. Il alloue un petit instantané par mark(). Le performance_budget de ce front-matter est la valeur de référence valable pour toute la documentation ; ce module ne l’impose pas.

Les chiffres de mémoire sont des données de diagnostic. Ils ne contiennent pas le contenu du document, mais un profil mémoire granulaire peut révéler des informations sur la taille et la forme de l’entrée. Traite les exports d’instantané comme de la télémétrie interne et applique l’exigence de nettoyage des journaux du projet avant de les partager en externe. Le module n’effectue aucune E/S et n’intègre aucune donnée externe. Consulte le modèle de menace du moteur dans /modules/core/security/.

Ce module n’affirme aucune revendication normative de la spécification PDF. C’est un diagnostic mémoire qui n’implémente aucun protocole standardisé dont les clauses devraient être citées. Sa justification architecturale se réfère à la vue qualité d’utilisation des ressources du cadre de description d’architecture ISO/IEC/IEEE 42010, ce qui relève d’un alignement sur les pratiques d’architecture, et non d’une citation PDF. La conformité du moteur est validée par l’oracle et les suites golden décrites dans /modules/core/conformance/.