json_decode默认关联模式导致内存暴增,应禁用true参数或改用流式解析;数组累积需分批/生成器处理;SplFixedArray须显式指定大小且避免误用;unset后需检查引用并手动触发GC。

json_decode 后数组暴增内存?关掉关联模式
默认 json_decode($json, true) 会把所有数字索引也转成字符串键,生成全关联数组——哪怕 JSON 是 [1,2,3],PHP 也会存成 ['0'=>1,'1'=>2,'2'=>3],多出哈希表开销和键字符串内存。实测百万条日志解析后内存翻 2–3 倍很常见。
- 确认结构是纯列表时,用
json_decode($json, false)得到stdClass对象,再用$obj->{0}访问 - PHP 7.4+ 可加
JSON_OBJECT_AS_ARRAY标志(但只作用于顶层,嵌套仍可能出问题) - 终极方案:改用
JsonStreamingParser类库,边流式读、边处理,完全不进内存
循环里不断 $arr[] = $item?改用生成器或分批
每次 $arr[] = $item 都可能触发底层哈希表扩容+重哈希,内存呈阶梯式上涨;更糟的是,整个数组生命周期内都占着内存,GC 不会及时回收。
- 能流式处理就别攒:数据库查 10 万行?用
PDO::FETCH_ASSOC+while($row = $stmt->fetch())逐行处理 - 必须返回集合?写成生成器:
yield $item,调用方用foreach (genData() as $item),内存恒定在 KB 级 - 实在要数组,就分批:每次查 500 条,处理完
unset($batch),再取下一批
用了 SplFixedArray 却没省下内存?检查初始化和赋值方式
SplFixedArray 只在「已知长度 + 纯整数索引 + 读多写少」时才比普通数组省内存。一旦用错,反而更耗资源。
- 必须显式指定大小:
$arr = new SplFixedArray(10000),否则退化为普通对象行为 - 只能用
$arr[123] = $val,不能用$arr[] = $val(会报错) - 遍历时内部仍会临时转成普通数组,所以
foreach性能优势有限;真要极致性能,用for($i=0; $igetSize(); $i++) - 转回普通数组必须用
$arr->toArray(),(array)$arr可能出意外
unset 了还是不释放?排查引用和 GC 延迟
unset($big_array) 只减引用计数,不等于立刻还给 OS。尤其在 CLI 脚本中,循环里反复创建又 unset,内存可能越积越多。
立即学习“PHP免费学习笔记(深入)”;
- 检查是否被其他变量引用:比如
$a = &$b后只unset($a)没用,得unset($b)或全部解除 - 函数返回引用、静态属性、全局变量残留,都会锁住内存
- CLI 脚本中关键节点手动打点:
echo "After unset: " . round(memory_get_usage() / 1024 / 1024, 2) . " MB\n" - 怀疑循环引用时,加
gc_collect_cycles()强制回收(但别滥用,它本身有开销)



















