bigywater.tech
Django · 68

文件上传的内存与临时文件机制

用户上传一个 200 MB 的文件,Django 会把它整个读进内存吗?什么时候写临时文件?这篇在真实 gunicorn 上直接量 worker 的内存,并看不同大小的上传得到什么对象。

2.5 MiB
FILE_UPLOAD_MAX_MEMORY_SIZE 默认值:不超过在内存,超过写临时文件
46 vs 246 MiB
上传 200 MiB 时 worker 峰值内存:默认(落盘)vs 阈值调到 1 GiB
FILE_UPLOAD_TEMP_DIR
指定临时文件目录,上传前后由 Django 创建与清理

内存还是磁盘

实测 · 本机执行输出
  上传  1 MiB → InMemoryUploadedFile     size=1048576
  上传  2 MiB → InMemoryUploadedFile     size=2097152
  上传  3 MiB → TemporaryUploadedFile    size=3145728  临时文件存在=True
  上传 50 MiB → TemporaryUploadedFile    size=52428800  临时文件存在=True
  (临时文件的目录: /var/folders/km/b69gr9cs3dv8qsm8rjjb4qqc0000gn/T ;视图返回时它还在,响应发出后被清理)

请求体是分块读取并交给「上传处理器」的。默认的 MemoryFileUploadHandler 在内容小于阈值时把它留在内存,超过则由 TemporaryFileUploadHandler 写入临时文件。

大文件的内存

实测 · 本机执行输出
  worker 起始 RSS ≈ 46 MiB;上传 200 MiB(TemporaryUploadedFile)期间峰值 RSS ≈ 46 MiB
实测 · 本机执行输出
  worker 起始 RSS ≈ 42 MiB;上传 200 MiB(InMemoryUploadedFile)期间峰值 RSS ≈ 246 MiB

默认设置下上传大文件不会撑爆内存;只有主动调大阈值才会。这不是说安全——磁盘临时文件占用与上传并发数成正比(本文没有测并发)。

临时目录

实测 · 本机执行输出
  上传 5 MiB → 临时文件目录: <实验目录>  是否等于指定目录: True

视图返回、响应发出后临时文件被清理(视图里能看到文件存在)。

分步演示:上传到哪里

文件上传的内存与临时文件
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。gunicorn 26.2 1 worker;客户端用 http.client 手工发送 multipart 流;内存每 20 ms 用 ps 采样
    • 没有验证:并发上传时磁盘占用、上传处理器的自定义(FILE_UPLOAD_HANDLERS)、反向代理(nginx)对请求体的缓冲、上传中途断开时临时文件的清理、Linux 上 /tmp 的 tmpfs 情形
    京ICP备2026067502号-1京公网安备11010502063487号