MNN LLM 手机上内存不足时如何用 use_mmap、kvcache_mmap 和 chunk 规避溢出?
2026/9/15 16:22:28 网站建设 项目流程

MNN LLM 手机上内存不足时如何用 use_mmap、kvcache_mmap 和 chunk 规避溢出?

【免费下载链接】MNNMNN: A blazing-fast, lightweight inference engine battle-tested by Alibaba, powering high-performance on-device LLMs and Edge AI.项目地址: https://gitcode.com/GitHub_Trending/mn/MNN

在手机端用 MNN-LLM 跑量化 LLM 时,有两类内存压力源:一是llm.mnn.weight权重文件加载进内存,二是推理过程中持续增长的 KV Cache。当设备可用内存吃不下这两部分时,进程可能因内存溢出被系统杀死。MNN 的 LLM 引擎在运行时配置文件config.json中提供了三个针对内存占用的配置项:use_mmap(权重不足时转写磁盘)、kvcache_mmap(KV Cache 不足时转写磁盘)和chunk(prompt 分块运行),三者可以组合使用,把峰值内存压到设备可承受的范围。

前提是你已经能按官方 LLM 文档完成模型导出和引擎编译:

  • 模型目录(model_dir)下包含推理所需的全部文件:config.jsonllm_config.jsonllm.mnnllm.mnn.weighttokenizer.mtok,以及可能的embeddings_bf16.bin
  • 编译引擎时打开了-DMNN_BUILD_LLM=ON

以 Android 为例的编译方式(官方文档给出的命令):

cd project/android mkdir build_64 ../build_64.sh -DMNN_BUILD_LLM=ON -DMNN_OPENCL=ON -DMNN_USE_LOGCAT=ON

mac / Linux 下则是:

make build cd build cmake ../ -DMNN_BUILD_LLM=ON make -j16

编译产物中会生成llm_demo工具,下面的配置和验证都围绕它展开。

在 config.json 中开启三个内存配置项

三个配置项的文档定义如下(见 docs/transformers/llm.md 的"推理配置"一节,英文文档 transformers/README.md 有相同说明):

配置项默认值作用
use_mmapfalse使用 mmap 方式,在内存不足时将权重写入磁盘,避免溢出。手机上建议设成true
kvcache_mmapfalse使用 mmap 方式,在内存不足时将 KV Cache 写入磁盘,避免溢出
chunk限制每次最大处理的 token 数,高于此值将分块运行,以减少内存占用,如chunk: 128
chunk_limits限制每次处理的 token 数,不在此范围内将分拆或者补零处理,如chunk_limits: [128, 1]存在chunk_limits时,chunk配置无效
tmp_path启用 mmap 相关功能时,写入磁盘的缓存目录

三点需要注意:

  1. use_mmap保护的是权重加载与驻留阶段,kvcache_mmap保护的是推理过程中的 KV Cache 增长,两者针对的是不同时刻的内存峰值,长 prompt 或多轮对话场景下通常都要评估。
  2. chunk影响的是单次处理 prompt 的长度:超过阈值的 prompt 会被分块运行。它降低的是 prefill 阶段的峰值内存,代价是分块计算,文档没有给出对应的性能损耗数据。
  3. tmp_path是 mmap 落盘目录,磁盘上要有足够空间存放被换出的权重/KV 数据。iOS 上文档给出了创建并设置临时目录的示例(Objective-C++):
NSString *tempDirectory = NSTemporaryDirectory(); llm->set_config("{\"tmp_path\":\"" + std::string([tempDirectory UTF8String]) + "\"}");

仓库中有一个可直接参考的 mmap 示例配置 mmap_config.json,其中use_mmap设为true

结合文档中的config.json示例,一个面向手机内存受限场景的完整配置(示例配置,tmp_path需替换为设备上的实际可写目录,Android 文档中的运行目录示例是/data/local/tmp/MNN/):

{ "backend_type": "cpu", "thread_num": 4, "precision": "low", "memory": "low", "use_mmap": true, "kvcache_mmap": true, "chunk": 128, "tmp_path": "/data/local/tmp/MNN/cache" }

其中precision: "low"表示尽量使用 fp16、memory: "low"表示开启运行时量化,二者是文档给出的默认内存/精度策略,与 mmap 配置相互独立,保留即可。

运行 llm_demo 并验证效果

配置好config.json后,用llm_demo验证(用法见文档"推理用法"一节):

# 交互式聊天 ./llm_demo model_dir/config.json # 针对 prompt.txt 中的每行进行回复 ./llm_demo model_dir/config.json prompt.txt

判断是否解决溢出问题的依据是:同一模型、同一 prompt,未开启 mmap/chunk 时会内存不足导致进程被杀或加载失败,开启后能正常完成一次完整生成并输出回复。文档没有给出专门的"mmap 已生效"日志,验证以"能否跑通并正常输出"为准。

在 Android 设备上,文档给出的运行方式是经过testCommon.sh推送并在设备上执行:

project/android/testCommon.sh ./llm_demo model/config.json

如果你还想定量对比开启 mmap 前后的性能影响,可以用llm_bench-mmp--mmap)参数做 A/B 测试,该参数指定模型加载时是否使用 mmap 技术,只接受一个值01

# 关闭 mmap ./llm_bench -m ./model/config.json -a cpu -p 512 -n 128 -rep 3 -mmp 0 # 开启 mmap ./llm_bench -m ./model/config.json -a cpu -p 512 -n 128 -rep 3 -mmp 1

文档对这一参数有一处明确结论:-mmp对模型推理性能无影响,即 mmap 换内存的方式本身不以推理速度为代价。

边界与相关选项

  • chunk_limitschunk互斥:配置了chunk_limits: [128, 1]之后chunk不再生效。chunk_limits的语义是把每次处理的 token 数约束在给定范围内(范围外分拆或补零),如果你需要固定块大小,用chunk即可,不要两个同时配。
  • KV Cache 还有第二条减内存路径attention_mode可以开启 KV Cache 量化,例如10为 FlashAttention + KV-INT8(文档标注精度几乎无损)、14为 FlashAttention + KV-TQ4(文档标注内存节省超过 30%,推荐 4B+ 模型使用,小模型精度损失较大)。它与kvcache_mmap不冲突:一个减少 KV Cache 的体积,一个在剩余空间仍不足时把它换出到磁盘。
  • 磁盘目录不可用时tmp_path指向的目录是权重与 KV Cache 的落盘位置,如果目录不可写,mmap 功能无法落盘。iOS 上建议按上文用NSTemporaryDirectory()获取系统临时目录;Android 上可参考文档 Hexagon 一节的运行目录习惯(/data/local/tmp/MNN/)。

三个配置项都收敛在config.json里,改动后重新运行llm_demo即可生效;如果目标设备内存仍然紧张,下一步的文档化方向是换更小的量化模型或更小的模型规格(如用llmexport.py--quant_bit 4重新导出 4bit 模型),而不是继续调这三个参数。

【免费下载链接】MNNMNN: A blazing-fast, lightweight inference engine battle-tested by Alibaba, powering high-performance on-device LLMs and Edge AI.项目地址: https://gitcode.com/GitHub_Trending/mn/MNN

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询