在 Mac 上,PyTorch 任务内存不足时,报错的最后会给一条建议:
RuntimeError: MPS backend out of memory (MPS allocated: 18.50 GiB, other allocations: 448.00 KiB, max allowed: 18.72 GiB). Tried to allocate 512.00 MiB on shared pool. Use PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.0 to disable upper limit for memory allocations (may cause system failure).我想知道照这条建议做会发生什么,于是在我的 48 GB M5 Pro(macOS 26.5.2,PyTorch 2.14.0)上以每步 512 MiB 填满 MPS 内存,每个设置跑一次,并用一个守护进程看着:交换增加 2 GB 就停止进程。结论有两条。在这台 Mac 上,默认上限比内存还大,所以内存不够的任务会滑进交换,永远走不到这个错误。另外,要降低上限需要两个变量,而不是一个。
“max allowed”是怎么来的
max allowed 就是上限:PYTORCH_MPS_HIGH_WATERMARK_RATIO 乘以 torch.mps.recommended_max_memory() 的返回值。我的 Mac 上这个值是 37.44 GiB,0.5 × 37.44 = 18.72 GiB,正是上面错误里的数字。日志里的 MPS allocated 与 torch.mps.current_allocated_memory() 一致,也就是张量占用的内存。查看你自己的基准值:
import torch
print(torch.mps.recommended_max_memory() / 2**30, "GiB")为什么 48 GB 的 Mac 会先进入交换
PyTorch 文档给出的 high 比例默认值是 1.7。在我的 Mac 上,这让上限大约是 63.6 GiB,比机器的内存还多。每个设置的结果如下:

| 设置 | 是什么停止了填充 | 持有的张量 | 运行期间的交换 |
|---|---|---|---|
| 默认值(1.7) | 守护进程 | 38.5 GiB | 6.1 → 12.0 GB |
| 0.0 | 守护进程 | 36.0 GiB | 5.1 → 9.8 GB |
| 1.0,low 1.0 | 守护进程 | 34.5 GiB | 4.6 → 8.7 GB |
| 0.8,low 0.8 | PyTorch,max allowed 29.95 GiB | 29.5 GiB | 无变化 |
| 0.5,low 0.5 | PyTorch,max allowed 18.72 GiB | 18.5 GiB | 无变化 |
用默认值、0.0 和 1.0 时,进程一超过 33.5 到 36.2 GB,交换就开始增长,而 PyTorch 始终没有报错:它的上限比内存的尽头还远。所以错误里自己给的建议 0.0,在这里没有带来任何能看到的变化。上限本来就够不着,PyTorch 里没有任何东西停下这次运行。
怎么设置:两个变量
只设置 high 比例,会在第一次调用 MPS 时失败:
$ PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.8 python fill.py
RuntimeError: invalid low watermark ratio 1.4在 Apple Silicon 上,low 比例默认是 1.4,而且不能大于 high(除非 high 是 0.0,也就是关闭上限)。两个都要设置:
PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.8 PYTORCH_MPS_LOW_WATERMARK_RATIO=0.8 python run.py在 Python 里设置,要在第一个张量放到 mps 之前。PyTorch 在 MPS 启动时读取它们,而不是在 import torch 时,之后的修改会被忽略:
import os
os.environ["PYTORCH_MPS_HIGH_WATERMARK_RATIO"] = "0.8"
os.environ["PYTORCH_MPS_LOW_WATERMARK_RATIO"] = "0.8"
import torch文档把 low 比例称为软上限,并写道“setting 0.0 disables adaptive commit and garbage collection”。我把它设成和 high 一样,没有单独测它的效果。
怎么选值
上限应当低于你的 Mac 在开着平常那些应用时真正空闲的内存。在我的机器上,1.0(37.44 GiB)已经太多,0.8(29.95 GiB)给出了干净的错误,没有交换。拿到干净的错误后,可以降低 batch size 或分辨率再试;而滑进交换的运行会先拖慢整台 Mac。
测试时的一个陷阱
我第一次运行时用 torch.ones 填充张量。默认设置下,它一直到了我设的 46 GiB 上限,既没有报错,也完全没有交换:macOS 会把内容相同的页面压缩到几乎为零。模型权重不会这样被压缩,所以在 Mac 上测内存要用随机数据。
模型真的装不下时
干净的错误只能告诉你模型装不下。对于由多个模型组成的流水线,只加载当前阶段的模型比任何比例都管用,这也是我写 stageload 的原因。填充脚本和上面每次运行的 trace 都在它的仓库里,见 bench/results/2026-10-13-mps-watermark。