Python删除类实例后psutil无法准确显示可用内存的原因及替代方案
问题原因与解决方案
核心原因
psutil的virtual_memory()统计的是系统全局内存状态,而Python解释器(及PyTorch这类依赖库)有自身的内存池机制:当删除对象并触发垃圾回收后,释放的内存会先被Python内存池保留,不会立刻归还给操作系统。这就导致psutil仍会将这部分内存标记为“已占用”,但Windows资源管理器统计的是实际归还给系统的内存,因此出现数据差异。
另外,PyTorch的CPU张量内存管理也有类似逻辑,释放的内存会被PyTorch内部缓存,而非直接交还系统。
解决方案
1. 统计当前Python进程的内存(而非系统全局)
使用psutil.Process()获取当前进程的内存使用情况,能准确反映你的Python程序实际占用的内存:
import psutil import gc import torch # 获取当前Python进程 proc = psutil.Process() # 分配内存 x = torch.randint(0,255,size=(300,3,200,200),dtype=torch.float32) conv = Modules.Conv2D(3,3,2,10,save_flag=False) print("进程占用物理内存(RSS):", proc.memory_info().rss / 1024 / 1024, "MB") # 删除实例并回收内存 del conv, x gc.collect() # 若使用GPU张量,需额外调用torch.cuda.empty_cache() # torch.cuda.empty_cache() print("进程占用物理内存(RSS):", proc.memory_info().rss / 1024 / 1024, "MB")
这里的rss(常驻集大小)是进程实际占用的物理内存,能精准体现代码执行过程中的内存变化。
2. 强制PyTorch释放CPU内存
对于PyTorch的CPU张量,除了触发GC,还可以手动强制释放内部缓存的内存(适用于PyTorch 1.6+):
import torch torch._C._empty_cpu_cache()
执行该方法后,PyTorch会将缓存的CPU内存归还给操作系统,再用psutil.Process()统计即可得到更准确的结果。
3. 细粒度内存分析工具
若需要逐行定位内存变化,可使用memory_profiler库:
from memory_profiler import profile @profile def test_memory(): x = torch.randint(0,255,size=(300,3,200,200),dtype=torch.float32) conv = Modules.Conv2D(3,3,2,10,save_flag=False) del conv, x gc.collect() torch._C._empty_cpu_cache() test_memory()
运行后会输出每一行代码的内存变化数据,便于精准排查内存释放情况。
4. Windows平台直接调用系统API
如果需要获取和资源管理器完全一致的系统内存数据,可通过ctypes调用Windows系统API:
import ctypes class MEMORYSTATUSEX(ctypes.Structure): _fields_ = [ ("dwLength", ctypes.c_ulong), ("dwMemoryLoad", ctypes.c_ulong), ("ullTotalPhys", ctypes.c_ulonglong), ("ullAvailPhys", ctypes.c_ulonglong), ("ullTotalPageFile", ctypes.c_ulonglong), ("ullAvailPageFile", ctypes.c_ulonglong), ("ullTotalVirtual", ctypes.c_ulonglong), ("ullAvailVirtual", ctypes.c_ulonglong), ("sullAvailExtendedVirtual", ctypes.c_ulonglong), ] def get_system_memory(): stat = MEMORYSTATUSEX() stat.dwLength = ctypes.sizeof(MEMORYSTATUSEX) ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat)) used_percent = stat.dwMemoryLoad free_mb = stat.ullAvailPhys / 1024 / 1024 total_mb = stat.ullTotalPhys / 1024 / 1024 return used_percent, free_mb, total_mb # 使用示例 used_pct, free_mb, total_mb = get_system_memory() print(f"已用内存: {used_pct}% 可用内存: {free_mb:.2f} MB")
该方法直接调用Windows内核接口,返回结果与资源管理器完全一致。
内容的提问来源于stack exchange,提问作者JosephM
相关产品推荐
相关产品推荐

