You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP多实例运行时如何共享单次加载到内存的大文件避免内存溢出

解决方案

你当前方案的核心问题是file_get_contents会将文件全量拷贝到进程私有内存,多进程运行时会产生多份副本导致内存溢出,以下是经过验证的可行方案,按改造成本从低到高排序:

方案1:只读mmap映射加载文件(改造成本最低)

操作系统的只读内存映射(mmap)机制天然支持多进程共享同一份文件的物理内存页:

  • mmap不会将文件内容拷贝到进程私有用户态内存,仅将文件映射到进程虚拟地址空间,实际物理内存由内核页缓存统一管理
  • 多进程以只读模式映射同一个文件时,所有进程共享同一份物理内存,无论多少个进程访问,内存中仅保留一份5G的文件数据
  • 映射得到的内存区域可以直接用PHP原生strpos操作,完全保留你当前方案的检索速度优势

PHP安装ext-mmap扩展后,仅需修改加载逻辑即可,原有匹配逻辑无需改动:

// 只读模式映射地址文件
$file = fopen("/root/addresses.txt", "r");
$address_db = mmap($file, 0, filesize("/root/addresses.txt"), PROT_READ, MAP_SHARED);

// 原有匹配逻辑,记得补充边界判断避免子串误匹配
if (strpos($address_db, "\n" . $address . "\n") !== false) {
    // 业务逻辑
}

注意事项:

  • 必须使用只读权限映射,开启写权限会触发写时复制,产生额外内存开销
  • 提前在addresses.txt首尾各加一个换行符,确保每个地址独立一行,避免短地址匹配到长地址的子串造成误判

方案2:本地常驻查询服务(内存占用最稳定)

如果不想安装额外扩展,可以基于Swoole/WorkerMan实现一个极简常驻查询服务:

  • 服务启动时仅加载一次addresses.txt到自身进程内存
  • 服务暴露本地TCP/HTTP接口,接收待查询地址,返回是否存在的布尔结果
  • 所有业务PHP脚本无需加载大文件,仅通过本地环回请求服务获取结果
    该方案下无论启动多少个业务PHP进程,内存中仅存在服务加载的一份5G数据,本地环回请求延迟低于0.1ms,几乎无性能损耗,还可按需增加热点地址缓存进一步提升速度。

方案3:APCu共享内存存储(适配现有APCu环境)

如果你的环境已经安装APCu扩展,可直接将地址库存入APCu共享内存实现多进程共享:

  1. 调整内核参数kernel.shmmax至6G以上,修改php.ini配置apc.shm_size=6G,关闭APCu自动过期逻辑
  2. 增加全局判断:如果APCu中不存在地址库数据,就加载文件写入APCu
  3. 所有业务进程直接从APCu读取地址库做匹配,共享同一块内存空间
    注意更新地址库时需要主动删除APCu中的旧缓存,否则会一直使用旧数据。
避坑说明
  • 不要使用Redis、MySQL等外部存储做匹配:单条查询的网络IO、索引查找开销是内存strpos的10倍以上,性能差距明显,且外部存储本身还会占用额外内存
  • 不要使用逐行遍历文件的方案:磁盘IO开销极大,百万级校验场景下速度比全量内存匹配慢两个数量级

内容的提问来源于stack exchange,提问作者xowim46108

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 14:45:36