
在过去几周,我在 Azure Kubernetes Service (AKS) 上运行了一组 RAM 密集型的容器工作负载,使用的是 Windows Server 节点池。虽然工作负载本身运行得很稳定,但在任务完成后我注意到节点内存长期处于异常状态,尤其是“Nonpaged Pool”和“Paged Pool”占用持续高居不下。唯一有效的手段似乎只有重启节点,但在生产环境中,这并不是一个理想的选择。因此,我开始研究是否可以“让节点恢复理智”,即在不重启节点的前提下恢复其内存状态。
一、在开始之前,我运行以下 PowerShell 命令来获取节点内存的详细分布:
Get-Counter "\Memory\Pool Nonpaged Bytes", "\Memory\Pool Paged Bytes", `
"\Memory\System Cache Resident Bytes", "\Memory\Modified Page List Bytes", `
"\Process(_Total)\Working Set" |
Select-Object -ExpandProperty CounterSamples |
Select-Object Path, @{Name = 'SizeGB'; Expression = { '{0:N2} GB' -f ($_.CookedValue / 1GB) } }
在运行工作负载前后,系统状态如下:
任务前(空闲状态):
- Nonpaged Pool: 0.56 GB
- Paged Pool: 0.85 GB
- Cache Resident: 0.38 GB
- Working Set Total: 4.35 GB
任务结束 25 小时后:
- Nonpaged Pool: 5.80 GB
- Paged Pool: 11.38 GB
- Cache Resident: 2.84 GB
- Working Set Total: 6.01 GB
可以看出,“Paged”和“Nonpaged Pool”分别暴涨了超过 10 GB,却没有在任务结束后释放。
二、排查与理解:为何内核池内存无法释放?
Windows 的 Nonpaged Pool 和 Paged Pool 属于内核内存,它们不会像用户态进程那样自动释放,尤其是由驱动程序、内核模式 API 或网络堆栈分配的资源。一旦分配,这些内存通常只有在明确的回收逻辑执行后才会释放,某些情况下甚至需要驱动卸载或系统重启。
在 AKS 的 Windows 节点中,以下几个组件可能是“内存泄露”来源:
- Host Networking Service (HNS) 与其相关的容器网络驱动
- Kubelet for Windows(管理 Windows 容器生命周期)
- 大型容器应用程序未正确释放句柄
- Hyper-V 虚拟交换机残留
三、可行的缓解方案(无需重启)
以下是我验证可行的几种方案,部分适用于生产环境下临时缓解:
1. 清理 HNS 网络残留
容器停止后,其网络接口信息有时不会及时清除,HNS 的资源分配会持续占用内核内存。
Get-HnsNetwork
查找所有非活跃的 HNS 网络,如果发现存在孤立网络,可以执行:
Get-HnsNetwork | Where-Object { $_.Name -like "nat" -or $_.Name -like "cbr*" } | Remove-HnsNetwork
⚠️ 注意:此操作可能会断开所有容器网络,建议配合 node cordon 和 drain 操作使用。
2. 重启 Kubelet 与容器运行时服务
Restart-Service kubelet
Restart-Service docker
这将清理 Kubelet 所维护的容器状态缓存,可能间接触发内核释放部分句柄资源。需注意:某些容器会被自动重建。
3. 定期强制回收内存缓存(Memory Compression 机制)
Windows 支持通过设置工作集限制来触发回收:
Get-Process | ForEach-Object {
Try {
$_.MinWorkingSet = 1MB
$_.MaxWorkingSet = 1MB
} Catch {}
}
这会将大多数进程的工作集压缩进 Standby List,有助于清空部分页池内容。
4. 使用 RAMMap 手动释放 Standby List(需远程桌面)
微软官方工具 RAMMap 可以用来手动清除 Standby Cache,对 system cache 类资源释放有奇效。
打开 RAMMap → “Empty” 菜单 → 选择 “Empty Standby List”。
5. 启用 System Managed Cache Trimming 策略
在某些版本的 Windows Server 中,可以通过注册表或组策略强制启用 aggressive trimming:
Set-ItemProperty -Path "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" `
-Name "LargeSystemCache" -Value 0
重启相关服务后生效(非系统重启)。
四、最佳实践建议
为了防止类似问题再次出现,我也采取了以下预防策略:
- 为 Windows 节点池设定定期维护窗口(例如每月一次的节点滚动更新)
- 避免长时间运行的单体大型容器,尽量将 RAM 使用峰值限制在物理内存的 60% 以下
- 使用 DaemonSet 监控 Nonpaged/Paged Pool 占用并告警
虽然 Windows 节点不像 Linux 那样有完善的 memory cgroup 控制和自动清理机制,但通过 HNS 网络清理、服务重启和进程压缩机制,我们可以在不重启节点的情况下有效释放部分内核内存资源。这一流程在我的 AKS 环境中显著降低了 Nonpaged Pool 占用,并避免了对服务的中断。
当然,在无法控制的情况下,节点重启仍是最彻底的手段。但希望本文能为同样面临问题的运维人员提供一条可选的“温和路线”。











