问题本质:WSL2 的虚拟磁盘 (ext4.vhdx) 膨胀

  • 核心机制:WSL2 使用一个动态扩展的虚拟硬盘文件(通常是 ext4.vhdx),位于 \\wsl$\<发行版名称>\ext4.vhdx 或 C:\Users\<用户名>\AppData\Local\Docker\wsl\...。这个文件会随着您在 WSL2 内部写入数据而自动增长,但默认情况下不会自动收缩。
  • Docker 的角色:当您运行 docker-compose up 时,Docker 会在 WSL2 内部创建容器、镜像、卷(Volumes)和临时文件。这些操作都会在 ext4.vhdx 文件中占用空间。
  • down vs up 的陷阱:
    • docker-compose down 会停止并删除容器,但不会删除镜像、构建缓存或a命名卷(named volumes)。
    • docker-compose up 会重新创建容器。如果您的 docker-compose.yml 中定义了 volumes,Docker 会创建新的卷来持久化数据(如数据库文件、日志等)。这些卷的数据会持续写入 WSL2 的虚拟磁盘。
    • 即使您删除了容器和镜像,只要卷(尤其是匿名卷或命名卷)中的数据没有被清理,ext4.vhdx 文件的大小就不会减小。

2. 为什么感觉“申请了没释放”?

您的感觉是对的,但对象是虚拟磁盘空间,而不是内存。

  • 写入操作:Docker 容器在运行时会不断写入日志、临时文件、数据库数据到其卷中。
  • 删除操作:docker-compose down 删除了容器的“外壳”,但卷里的“内容”还在。
  • 磁盘文件:WSL2 的 ext4.vhdx 文件已经为这些写入操作分配了物理磁盘空间。即使文件系统(ext4)内部标记了这些数据为可覆盖,ext4.vhdx 这个宿主机上的文件大小也不会自动变小。

  1. 在 Docker 正常运行的情况下,以及运行你需要的容器时,执行 `docker system prune -a --volumes` 清理未使用的资源。

这会删除:所有停止的容器、所有未使用的镜像、所有构建缓存、所有未被容器使用的卷。

⚠️ 注意:这会删除您的数据卷!请确保数据库等重要数据已备份。

  1. prune --volumes 会删除未使用的卷,从而在 WSL2 文件系统内部“制造空洞”。

这些“空洞”是 接下来compact vdisk 能够压缩空间的前提。

  1. 退出docker desktop程序。在 PowerShell (管理员) 中执行:wsl –shutdown
  2. 依次执行下面命令
  3. diskpart

select vdisk file="D:\PPT\images\DockerDesktopWSL\disk\docker_data.vhdx"

attach vdisk readonly

compact vdisk

detach vdisk

exit

这些命令是在 Windows 的磁盘管理工具 diskpart 中执行的,用于对虚拟硬盘文件(.vhdx)进行“瘦身”操作。

select vdisk file="D:\PPT\...\docker_data.vhdx"

作用:告诉 diskpart,“我要操作的是这个路径下的 .vhdx 文件”。

类比:就像你打开一个文件编辑器,然后选择“打开文件”一样。这一步是选中目标虚拟磁盘。

attach vdisk readonly

作用:将这个 .vhdx 文件“挂载”为一个虚拟磁盘,但以只读方式加载到系统中。

发生了什么:

Windows 会把这个 .vhdx 文件当作一个物理硬盘来对待。

系统可能会自动分配一个盘符(如 F:),但因为是 readonly,你只能看,不能改。

这一步是必须的,因为只有挂载后,Windows 才能访问这个虚拟磁盘内部的文件系统,从而知道哪些数据块是“空的”(可以压缩掉)。

为什么用 readonly?

安全!防止在压缩过程中意外修改文件,导致 Docker 数据损坏。

compact vdisk

作用:这是核心命令——压缩虚拟磁盘文件的物理大小。

它做了什么?

扫描整个 .vhdx 文件。

找出那些在虚拟磁盘内部被标记为“已删除”或“未使用”的数据块(即“空洞”)。

告诉 NTFS 文件系统:“这部分空间其实不需要占用物理硬盘,可以释放了。”

最终结果:.vhdx 文件在磁盘上的实际占用大小(Size on disk) 减小。

举个例子:

你的 docker_data.vhdx 显示大小是 50GB,但它在磁盘上占用了 80GB(因为写入过大量日志、镜像等)。

经过 compact vdisk 后,如果清理得当,它可能回到 20GB 的物理占用。

detach vdisk

作用:卸载(断开)之前挂载的虚拟磁盘。

类比:就像你安全弹出 U 盘一样。确保没有程序再访问它。

5. exit

作用:退出 diskpart 工具,回到 PowerShell 或 CMD。


⏳ 为什么 compact vdisk 执行这么慢?

这是一个非常常见的现象,尤其是当你的 .vhdx 文件很大(比如几十 GB)时。原因如下:

需要扫描整个文件

compact vdisk 必须读取 .vhdx 文件的每一个数据块,检查它是否为空。

如果文件是 50GB,它就要扫描 50GB 的数据,这本身就是 I/O 密集型操作。

NTFS 文件系统的碎片化

随着时间推移,.vhdx 文件本身在 NTFS 分区上可能变得碎片化。

操作系统需要跳来跳去读取文件的不同部分,大大降低速度。

SSD/HDD 性能限制

即使是 SSD,连续读取大文件也需要时间。

如果你的磁盘负载高(后台有杀毒、索引服务等),速度会更慢。

WSL2 内部文件系统未“清零”

这是最关键的一点!

compact vdisk 只能压缩那些物理上为零的块(zero-filled blocks)。

如果你在 WSL2 中删除了一个 10GB 的日志文件,文件系统标记这块空间为空,但物理数据还在(可能是随机垃圾数据)。

compact 看不到“空洞”,所以无法压缩。

更多推荐