perf(php): 优化大数组内存分配策略

- 引入 MAX_BYTES_IN_STACK 常量控制栈上数组大小限制
- 实现超过 65536 字节的数组自动转到堆上分配
- 在 StdArrayParser 中计算数组总字节数并存储到 bytes 属性
- 根据数组大小选择栈上初始化或堆上 unique_ptr 分配方式
- 避免大数组在栈上分配导致的内存溢出问题
pull/1/head
韩天峰 4 months ago
parent 30ad4dbb0e
commit 58a4702ed2
  1. 10
      src/Php/CompilerBase.php
  2. 7
      src/Php/Parser/StdArrayParser.php

@ -102,6 +102,8 @@ class CompilerBase extends \PhpAot\Core\Translator
public const string OP_NOT_EMPTY = 'notEmpty';
public const string OP_REFVAL = 'toReference';
public const string OP_NOP = "if (0) {}\n";
// 超过65536字节的数组,将从栈上转移到堆
public const int MAX_BYTES_IN_STACK = 65536;
protected string $lang = 'PHP';
protected string $cppCompiler = '';
protected array $literalStrings = [];
@ -5367,8 +5369,12 @@ class CompilerBase extends \PhpAot\Core\Translator
$code .= $this->getIndent();
if ($type === self::TYPE_STD_ARRAY) {
$info = $this->context->stdArrays[$name];
$code .= "auto {$name}_unique_ptr = std::make_unique<{$info['decl']}>();\n";
$code .= $this->getIndent() . ' auto &' . $name . ' = *' . $name . '_unique_ptr;';
if ($info['bytes'] > self::MAX_BYTES_IN_STACK) {
$code .= "auto {$name}_unique_ptr = std::make_unique<{$info['decl']}>();\n";
$code .= $this->getIndent() . ' auto &' . $name . ' = *' . $name . '_unique_ptr;';
} else {
$code .= $info['decl'] . ' ' . $name . '{};';
}
} else {
$code .= $type . ' ' . $name;
if ($type === self::TYPE_INT or $type === self::TYPE_FLOAT or $type === self::TYPE_BOOL) {

@ -108,6 +108,7 @@ trait StdArrayParser
{
$tmp = $expr;
$nesting = [];
$totalBytes = 0;
while (true) {
if (count($tmp->args) !== 2) {
@ -116,6 +117,7 @@ trait StdArrayParser
if (!$this->isScalarInt($tmp->args[1]->value)) {
$this->fatalError($tmp, 'std::array() expects second argument to be an integer');
}
$byte = 0;
$size = $tmp->args[1]->value->value;
$nesting[] = $size;
$typeExpr = $tmp->args[0]->value;
@ -126,12 +128,15 @@ trait StdArrayParser
switch ($typeExpr->name->name) {
case 'type_int':
$type = self::TYPE_INT;
$byte = 8;
break;
case 'type_float':
$type = self::TYPE_FLOAT;
$byte = 8;
break;
case 'type_bool':
$type = self::TYPE_BOOL;
$byte = 1;
break;
default:
$this->fatalError($tmp, 'An incorrect `std::array` definition');
@ -139,6 +144,7 @@ trait StdArrayParser
}
break;
}
$totalBytes += $size * $byte;
if ($this->isStaticCall($typeExpr)) {
$tmp = $typeExpr;
if (!$this->isNameExpr($tmp->class) || !$this->isIdExpr($tmp->name) || $tmp->class->toString() !== 'std' || $tmp->name->toString() !== 'array') {
@ -158,6 +164,7 @@ trait StdArrayParser
'decl' => $decl,
'type' => $type,
'sizes' => array_reverse($nesting),
'bytes' => $totalBytes,
];
return '// ' . $decl;
}

Loading…
Cancel
Save