跳转到内容

性能:内存碎片分析器

Performance 模块刻意保持精简。它只提供一个用于观测的工具——MemoryFragmentationAnalyzer——用于在引擎工作中标记的各个区间测量峰值内存与保留内存。该接口还包含此工具生成的不可变快照。它不会强制执行预算、执行限流,也不会改变引擎行为。

范围与稳定性。 本模块真正的接口是两个类 (MemoryFragmentationAnalyzerMemoryFragmentationSnapshot)。它并非 用于逐项操作的预算强制执行工具。performance_budget 值是每个模块 front-matter 中的文档约定,而非本模块会强制执行的设定。该接口是 experimental:它是一个诊断工具, 于 @since 3.2.0 引入,其快照结构可能会继续演进。

Terminal window
composer require nextpdf/core:^3

对 PDF 引擎而言,资源使用率是首要质量考量。支撑这一考量的最小可观测量,是区分峰值内存(区间内的最高水位)与保留内存(区间结束后仍占用的部分)。本模块精确测量的正是这一点,不额外做其他事。

MemoryFragmentationAnalyzer 仅用于观测——它不会改变 writer 或文档状态。reset() 会执行一次 GC 循环并重置 PHP 的峰值计数器,使后续测量都归属于本次重置后的区间。mark(string $label) 会在一个带标签的点捕获一份 MemoryFragmentationSnapshotsnapshots() 会返回已捕获的系列数据。peakDelta()retainedDelta() 会报告整个运行过程中峰值内存与保留内存的变化量。

MemoryFragmentationSnapshot 是一个 final readonly 值对象:它表示一个带标签的测量点,包含 transientBytes()(峰值减去保留——曾被使用后又释放的内存)、retentionRatio()(保留除以峰值),以及用于导出的 toArray()。瞬态字节数偏高但保留比率偏低,表示存在频繁的内存周转,而缓冲区重用策略可能有机会消除这种周转。这两个类均为 @since 3.2.0

主要成员职责
MemoryFragmentationAnalyzerreset(), mark(string $label), snapshots(), peakDelta(), retainedDelta()仅供观测的内存分析器(@since 3.2.0
MemoryFragmentationSnapshottransientBytes(), retentionRatio(), toArray()不可变的带标签测量值(@since 3.2.0

运行 composer docs:generate-api-php -- --module=Performance 即可获得完整的 PHPDoc 表格。

将一段热点路径包起来,然后读取变化量。

<?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());

包裹一次渲染过程,并将碎片快照发送到指标接收端;当瞬态字节数较高而保留比率较低时,将其视为周转信号。

<?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() 会调用 gc_collect_cycles()memory_reset_peak_usage()。它会对 PHP 的峰值计数器产生进程级全局影响。不要在同一个请求中,将它与另一个也会读取峰值计数器的组件交错使用。
  • 测量结果归属于自上一次 reset() 以来的区间。如果在 mark() 之前没有先调用 reset(),则会从进程启动开始测量,而这通常不是你想要的结果。
  • 这是一个诊断工具,而非控制手段。它绝不会限流或中止工作;不要基于它构建背压机制。
  • 可复现性概况为 structural:字节数值取决于运行时、分配器与 GC 状态。即便执行相同的逻辑工作,两次运行的数值也会有所不同。

分析器自身的开销包括在 reset() 上执行一次 GC 循环,以及每次 mark() 进行一次 hrtime() / memory_get_* 读取;相对于被观测的工作,这些开销可以忽略不计。每次 mark() 都会分配一份小型快照。本 front-matter 中的 performance_budget 是面向整套文档的参考数值;本模块并不会强制执行它。

内存数值属于诊断数据。它们不包含文档内容,但细粒度的内存概况可能泄露与输入大小和形态相关的信息。应将快照导出视为内部遥测数据,并在对外共享之前先完成项目要求的日志脱敏。本模块不执行任何 I/O,也不嵌入任何外部数据。参见 /modules/core/security/ 中的引擎威胁模型。

本模块不对 PDF 规范做出任何规范性主张。它是一个内存诊断工具,并未实现任何需要引用其条款的标准化协议。其架构理据引用了 ISO/IEC/IEEE 42010 架构描述框架中的资源使用率质量视角,这是一种架构实践层面的对齐,而非 PDF 引用。引擎合规性由 /modules/core/conformance/ 中描述的 oracle 与 golden 套件来验证。