# 压缩Hyper-V的虚拟硬盘（VHD/VHDX）释放空间

针对你的情况，核心问题在于Hyper-V的虚拟硬盘（VHD/VHDX）具有“只增不减”的特性。即使你在虚拟机（Ubuntu）内部删除了大量文件，物理机上的VHD文件依然保持着膨胀后的大小，不会自动释放空间。

目前的困境是：

- **物理机（宿主机）D盘**：剩余空间 43.4 GB。
- **虚拟机（客户机）内部**：已删除文件，显示有大量空闲空间。
- **目标**：对虚拟机文件进行压缩（精简），释放物理机D盘空间。

**结论：** 在D盘剩余43.4 GB的情况下，**只要你的虚拟机VHD文件不是特别巨大（例如超过100GB），通常是可以进行压缩处理的**。

以下是具体的操作步骤，分为“零填充”和“压缩”两个阶段。

---

### 第一阶段：在虚拟机（Ubuntu）内部操作

这一步的目的是告诉硬盘：“这些块现在是空的，可以被回收”。

1. **安装 `zerofree` 工具（推荐方式）** 在Ubuntu终端中执行：
    
    ```bash
    sudo apt-get update
    sudo apt-get install zerofree
    
    ```
2. **执行零填充** 由于`zerofree`不能在挂载（读写）状态下运行根分区，你需要进入**恢复模式**或使用**Live CD**。但有一个更简单的方法，使用 `dd` 命令（虽然不如zerofree彻底，但在运行中可用）：
    
    **方法 A：使用 dd 命令（无需重启，操作简单）** 在Ubuntu终端执行以下命令，它会在磁盘空闲处写入全0文件，填满磁盘后再删除。
    
    ```bash
    # 这一步会占用所有剩余空间，直到报错“设备上没有空间”，这是正常的
    sudo dd if=/dev/zero of=/zero.file bs=1M
    
    # 报错后，删除这个文件
    sudo rm -f /zero.file
    
    # 刷新文件系统
    sync
    
    ```
    
    **方法 B：使用 zerofree（更彻底，但需要重启进单用户模式）** 如果方法A效果不佳，可尝试此法。
    
    
    1. 重启虚拟机，在Grub菜单选择“恢复模式”（Recovery Mode）或按 `e` 编辑启动项，将 `ro recovery nomodeset` 改为 `rw single init=/bin/bash`。
    2. 卸载根分区（假设是 /dev/sda1）：`umount /dev/sda1`
    3. 执行：`zerofree -v /dev/sda1`

---

### 第二步：在物理机（宿主机 Windows）上操作

这一步是将虚拟机里刚才标记的“全0”区域真正地从VHD文件中剔除。

**注意：** 必须先**关闭**虚拟机。

#### 方法一：使用 Hyper-V 管理器（图形化界面，最安全）

1. 打开物理机上的 **Hyper-V 管理器**。
2. 在右侧操作栏点击 **“编辑磁盘...”**。
3. **定位磁盘**：浏览找到你的虚拟机在D盘对应的 `.vhdx` 文件。
4. **选择操作**：选择 **“压缩”**。 
    - *解释*：“压缩”操作会移除未使用的块。
    - *注意*：如果“压缩”是灰色的或者不可选，说明该VHD文件有快照，必须先删除快照。
5. **完成**：按照向导点击完成。系统会开始处理，这个过程需要读取整个VHD文件并写入一个新的、更小的文件。

**空间预警：**

- “压缩”过程需要临时的物理空间。Hyper-V通常会创建一个新的小文件，处理完后再替换旧文件。
- **如果 D盘剩余的 43.4 GB 小于虚拟机当前“实际已用数据量”（注意不是总大小，是删文件前的大小），操作可能会失败，提示空间不足。**

#### 方法二：使用 PowerShell（如果图形界面失败）

以管理员身份运行 Windows PowerShell：

```powershell
# 语法：Optimize-VHD -Path "VHD文件路径" -Mode Full
Optimize-VHD -Path "D:\你的路径\你的虚拟机磁盘.vhdx" -Mode Full

```

---

### 如果D盘空间实在不够怎么办？

如果上述“压缩”步骤提示空间不足（因为43.4GB可能不足以支撑重写过程），你有两个变通方案：

#### 方案 A：利用 C 盘空间（如果有）

1. 将虚拟机的 `.vhdx` 文件**移动**到 C 盘（C盘有69GB可用）。
2. 在 Hyper-V 设置里重新指向 C 盘的磁盘文件。
3. 在 C 盘执行上述的“压缩”操作。
4. 压缩完成后，文件变小了，再移回 D 盘。

#### 方案 B：导出再导入（最稳妥的瘦身法）

这种方法不需要额外的临时空间，但耗时较长。

1. 在 Hyper-V 管理器中，右键点击该虚拟机 -&gt; **导出**。
2. 选择一个有足够空间的路径（或者利用导出过程自动瘦身，但这取决于版本）。
3. 更好的方式是：**新建一个虚拟机**，创建一个比当前小的新VHDX，然后将旧数据迁移过去（这种方法太繁琐，不推荐）。

### 总结建议

1. 先在 **Ubuntu** 里运行 `dd` 命令填零并删除。
2. **关机**。
3. 尝试直接用 Hyper-V 的 **“编辑磁盘” -&gt; “压缩”** 功能。
4. 如果报错空间不足，先将 `.vhdx` 文件**剪切到 C 盘**，在 C 盘压缩完变小后，再移回 D 盘。

明白了，虚拟机文件总量超过 3T，而物理机 D 盘剩余空间只有 43.4 GB。

这个情况非常关键。直接回答你：**在 D 盘剩余空间不足的情况下，对 3T 的虚拟机进行“压缩/精简”操作极其危险，且通常无法完成。**

原因如下： Hyper-V 的压缩（精简）机制通常需要创建一个“临时副本”或者移动数据块。对于 3T 的文件，即使只用了 100G，压缩过程往往也需要一定的“周转空间”来重新排列数据块。43GB 的剩余空间对于 3TB 级别的文件操作来说，就像是试图用一个小勺子去挖空一座山，空间完全不够周转，极大概率会导致操作失败，甚至损坏虚拟机文件。

**但是，你还有一个机会，不需要物理机腾出空间，直接在虚拟机内部通过 PowerShell 命令进行“在线精简”。**

请严格按照以下步骤操作，这是目前最安全、无需额外物理空间的方案：

### 核心方案：使用 PowerShell 进行在线优化（推荐）

这个方法利用了 Windows 10/Server 2016 及以上版本 Hyper-V 的新特性，可以直接通知虚拟硬盘回收未使用的块，而不需要创建巨大的临时文件。

#### 1. 虚拟机内部操作 (Ubuntu)

你需要先让 Ubuntu 系统把“已删除文件”的状态告诉底层硬盘。

1. 确保虚拟机内安装了 `open-vm-tools` 或者 `hyperv-daemons`（通常 Kylin/Ubuntu 自带或需安装）： `sudo apt-get install linux-virtual-lts-xenial` (或者确保 `hv_utils` 模块已加载) 检查模块：`lsmod | grep hv_utils` 如果有输出，说明驱动正常。
2. **执行“discard”操作（关键步骤）**： 在 Ubuntu 终端中运行以下命令，手动触发 TRIM/Discard 指令： `sudo fstrim -v /` *如果还有挂载其他数据盘，也要对它们执行此命令，例如 `sudo fstrim -v /data`*
    
    **注意：** 如果命令成功执行，它会显示“XXX bytes were trimmed”。这一步仅仅是告诉 Hyper-V：“这些块我不用了”。

#### 2. 物理机操作 (Windows 宿主机)

现在需要在宿主机上强制 Hyper-V 回收这些空间。

1. **关闭虚拟机**（必须关机，不能是保存状态）。
2. 以**管理员身份**打开 Windows PowerShell（不是 CMD）。
3. 执行以下命令（请替换为你的实际路径）：
    
    ```powershell
    Optimize-VHD -Path "D:\你的虚拟机文件夹\你的虚拟硬盘文件.vhdx" -Mode Full
    
    ```
    
    *注意：如果你的虚拟机文件是 `.vhd` 格式，这个命令可能不支持，必须是 `.vhdx`。如果是 `.vhd`，你只能转为 vhdx 或者使用导出法。*

### 备选方案：如果上述方法失败（空间实在不足）

如果 `Optimize-VHD` 报错提示空间不足，或者你的虚拟硬盘是固定大小（Fixed Size）而不是动态扩展（Dynamic），那么你面临一个尴尬的境地：**物理机 D 盘必须腾出空间。**

因为 3T 的文件，任何涉及“移动”或“复制”的操作（如导出虚拟机、编辑磁盘）都需要至少等同于“已用数据量”的临时空间。

**如果必须压缩且上述方法无效，你只有两条路：**

1. **物理腾挪（最稳妥）：** 找一块移动硬盘，把 D 盘其他不重要的文件移走，**务必腾出至少 50GB - 100GB 的空闲空间**。 然后使用 Hyper-V 管理器：
    
    
    - 右键虚拟机 -&gt; **导出**（导出到一个临时文件夹）。
    - 导出完成后，删除原来的虚拟机和原来的 3T 文件。
    - 将导出的虚拟机重新**注册**进来。 *这是唯一能 100% 确保把 3T 文件瘦身的方法，但前提是你得有地方存放那个“导出”过程的临时文件。*
2. **拆分存储（如果有多余硬盘）：** 如果你的电脑有 E 盘或其他盘，可以将虚拟机的硬盘文件移动到那个盘，那个盘空间如果大，就在那个盘上进行压缩操作。

### 总结建议

1. 先在 Ubuntu 里运行 `sudo fstrim -v /`。
2. 关机。
3. 在 Windows PowerShell (管理员) 里运行 `Optimize-VHD -Path "D:路径xxx.vhdx" -Mode Full`。
4. **千万不要**尝试使用“编辑磁盘 -&gt; 压缩”向导，那个向导在空间不足时极容易报错卡死。

如果 `Optimize-VHD` 提示空间不足，那你只能去清理 D 盘其他文件了，否则神仙难救。