Python内存管理疑问:pybind11与原生对象内存释放差异原因
关于pybind11封装对象与Python原生对象删除后内存回收差异的疑问
我发现删除pybind11封装的对象时,内存不会归还操作系统,而是留存于内存池中;但删除Python原生对象时,内存会直接归还给系统。我通过以下测试代码验证了该现象,特向大家询问造成这一差异的原因。因某些原因无法展示完整代码,故使用伪代码说明:
pybind11测试代码
def observe_mem_func(): print('Memory already in use:', psutil.Process(os.getpid()).memory_info().rss // 1024 // 1024 // 1024) # 初始化pybind11对象前显示系统已用内存 observe_mem_func() # init_pybind_object函数会返回两个pybind11封装的对象 pybind_object_1, pybind_object_2 = init_pybind_object() # 初始化pybind11对象后显示系统已用内存 observe_mem_func() # 删除pybind11对象 del pybind_object_1 del pybind_object_2 gc.collect() # 删除pybind11对象后显示系统已用内存 observe_mem_func() # 再次初始化对象,可见内存从内存池中获取,说明内存未归还系统 pybind_object_3, pybind_object_4 = init_pybind_object() observe_mem_func()
运行结果(单位:G)
Memory already in use: 0
Memory already in use: 1
Memory already in use: 1
Memory already in use: 1
Python原生对象测试代码
def observe_mem_func(): print('Memory already in use:', psutil.Process(os.getpid()).memory_info().rss // 1024 // 1024 ) class Base: def __init__(self, str) -> None: self.str = str def init_base(): with open("test_code/file.txt", 'r') as fp: return Base(fp.read()) a = [] print("Init Base object") for i in range(5): a.append(init_base()) observe_mem_func() print("Del object") for i in range(5): a.pop() observe_mem_func()
运行结果(单位:M)
Init Base object
Memory already in use: 215
Memory already in use: 246
Memory already in use: 277
Memory already in use: 307
Memory already in use: 338
Del object
Memory already in use: 307
Memory already in use: 277
Memory already in use: 246
Memory already in use: 215
Memory already in use: 185
差异原因分析
- 内存分配器不同
Python原生对象使用解释器自带的pymalloc分配器,针对大对象(如测试中读取大文件的字符串),pymalloc会在对象回收后将内存归还给操作系统;而pybind11封装的C对象由C默认分配器(malloc/new)分配,这类分配器会把释放的内存留在内部内存池,用于后续快速分配,不会立即归还系统。 - 内存管理控制权差异
Python原生对象的内存完全由解释器掌控,可根据自身策略决定是否归还内存;pybind11对象的底层内存由C运行时管理,Python仅能触发对象析构,无法干预C分配器的内存池行为。 - 测试场景的印证
pybind11测试中再次创建对象时内存未增长,说明内存池复用了之前释放的内存;Python原生测试中内存随对象删除逐步下降,是因为大对象使用系统分配器,释放时直接归还操作系统。
内容的提问来源于stack exchange,提问作者Dylan
相关产品推荐
相关产品推荐

