frankenphp 默认启用 max_memory_upload 机制,小文件(默认≤2mb)全载入内存,大文件分段处理;需设 max_memory_upload=0 禁用内存缓冲,并同步调大 upload_max_filesize 和 post_max_size,配合流式读取、move_uploaded_file 或 hash_file 避免 oom,且须手动清理 $_files 临时文件。

FrankenPHP 默认上传机制会把小文件全载入内存
FrankenPHP 对文件上传的处理和 PHP-FPM 不同:它默认启用 max_memory_upload 机制,小于该阈值的上传文件会直接读进内存(而非写入临时磁盘),但这个阈值默认极小——约 2MB。这意味着上传一个 5MB 的 PDF,前 2MB 在内存,剩下 3MB 才落盘;而上传一个 1.5MB 的 ZIP,整个文件就常驻内存了。这不是 bug,是设计取舍:小文件快,大文件可控。但如果你没意识到这点,$_FILES 看似正常,实际已悄悄吃掉大量内存。
调大 max_memory_upload 并配好 upload_max_filesize
要让大文件从一开始就不进内存,得主动关闭“内存优先”策略。FrankenPHP 通过环境变量或配置控制该行为:
-
max_memory_upload设为0:彻底禁用内存缓冲,所有上传一律落盘(推荐用于文件服务类应用) -
max_memory_upload设为具体字节数,比如8388608(即 8MB):仅 ≤8MB 的文件走内存,其余落盘 - 必须同步检查并调大
upload_max_filesize和post_max_size,否则上传超限直接 413,连落盘机会都没有 - 这些参数需在 FrankenPHP 启动前生效——Docker 中用
environment,systemd 中写Environment=,CLI 模式下用FRANKENPHP_MAX_MEMORY_UPLOAD=0 frankenphp run
后端接收时别用 file_get_contents($_FILES['file']['tmp_name'])
即使文件已落盘,常见错误仍是“一次读完”:
-
file_get_contents()会把整个临时文件加载进 PHP 内存,对 100MB 视频等于瞬间申请 100MB+ 连续内存,极易触发 OOM - 正确做法是流式处理:
$fp = fopen($_FILES['file']['tmp_name'], 'rb')→fread($fp, 8192)分块读 → 处理完fclose($fp) - 如果目标是存到 S3 或本地磁盘,优先用
move_uploaded_file()(它不读内容,只改 inode),再由后续任务异步处理 - 若必须校验哈希,用
hash_file('sha256', $_FILES['file']['tmp_name'])—— 它内部就是流式计算,不占额外内存
注意 memory_limit 和容器限制的协同关系
光调上传参数不够。worker 模式下,一个常驻进程可能同时处理多个上传请求:
- 假设
num_threads = 8,每个上传请求峰值内存 60MB(含框架、OPcache、临时 buffer),那仅上传就可能吃掉 480MB - 此时
memory_limit = 256M是无效的——它只管单请求,不限制线程池总内存 - 真正起作用的是容器
mem_limit(如1g)和系统 cgroup,必须确保num_threads × 单请求实测峰值 - 用
memory_get_peak_usage(true)在上传逻辑末尾打点,确认真实占用,别信理论值
最容易被忽略的是:FrankenPHP 不会自动清理 $_FILES 临时文件。worker 模式下,若你没显式 unlink($_FILES['file']['tmp_name']) 或 move_uploaded_file(),这些文件会一直留在磁盘,直到进程重启或系统清理——不是内存问题,但会耗尽 inode 或填满 /tmp。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











