PHP 執行報錯 Fatal error: Allowed memory size of 134217728 bytes exhausted 表示腳本申請記憶體超過 `memory_limit` 設定。本文提供分層級解決方案(配置修改、運行時調整、代碼優化)、記憶體分析工具與預防最佳實踐。
Allowed memory size of 134217728 bytes exhausted
# 134217728 bytes = 128 MB (預設值)
# 8388608 bytes = 8 MB (舊版預設)
# 1. 定位 php.ini
php --ini
# 或 phpinfo() 顯示 Loaded Configuration File
# 2. 修改 memory_limit
memory_limit = 256M # 建議 256M-512M,-1 代表無限制(危險)
# 3. 重啟服務
systemctl restart php-fpm # 或 apache2 / nginx
<?php
// 必須在記憶體密集操作之前呼叫
ini_set('memory_limit', '512M'); // 字串格式,單位 M/G/K
// 檢查當前限制
echo 'Current limit: ' . ini_get('memory_limit');
> ⚠️ 若 `php.ini` 設定 `disable_functions = ini_set` 則無效。
# .htaccess (Apache)
php_value memory_limit 256M
# .user.ini (PHP-FPM/通用,目錄級遞歸生效)
memory_limit = 256M
| 問題模式 | 優化方案 | 記憶體釋放效果 |
|---|---|---|
| 一次性讀取大檔案 | `file_get_contents` → `fopen` + `fgets` 逐行處理 / Generators | 從 O(n) 降為 O(1) |
| 大陣列長期駐留 | 分批處理 + `unset($largeArray)` + `gc_collect_cycles()` | 即時釋放 |
| 資料庫大結果集 | `fetchAll()` → 游標 `fetch()` 迴圈 / PDOStatement::fetch | 避免雙份複製 |
| 圖片處理 (GD) | 處理完立即 `imagedestroy($resource)` | 釋放 C 層記憶體 |
| 字串大量拼接 | `.`= → `[]` 陣列收集最後 `implode()` / `yield` | 減少中間複製 |
| Composer autoload 過重 | `composer dump-autoload -o` 生成 classmap | 減少檔案掃描 |
<?php
function memUsage(string $label = ''): string {
$unit = ['B', 'KB', 'MB', 'GB'];
$mem = memory_get_usage(true); // true = 含系統分配
$peak = memory_get_peak_usage(true);
$i = floor(log($mem, 1024));
return sprintf("%s: 當前 %.2f %s / 峰值 %.2f %s",
$label, $mem / 1024**$i, $unit[$i], $peak / 1024**$i, $unit[$i]);
}
// 關鍵節點插入
echo memUsage('讀取檔案前') . "\n";
$data = file('huge.log');
echo memUsage('讀取檔案後') . "\n";
unset($data);
echo memUsage('釋放後') . "\n";
# php.ini
zend_extension=xdebug.so
xdebug.mode=profile
xdebug.output_dir=/tmp/xdebug
xdebug.profiler_output_name=cachegrind.out.%p
# 執行腳本後分析
webgrind /tmp/xdebug
composer require --dev php-memory-profiler/php-memory-profiler
<?php
use MemoryProfiler\MemoryProfiler;
$profiler = new MemoryProfiler();
$profiler->start();
// ... 執行代碼 ...
$report = $profiler->stop();
echo $report->getReport();
fputcsv 逐行寫入檔案流,或 box/spout 串流式寫入器。結合配置調整、代碼優化、持續監控三位一體,能從根本上解決 PHP 記憶體耗盡問題,保障服務穩定運行。