You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何准确统计Python对象的内存占用?

如何准确计算对象删除后实际释放的内存大小

核心问题拆解

你要的不是对象本身的大小,而是对象被删除后真正能回收的内存量——这需要区分对象持有的引用中,哪些是仅被该对象引用的(可回收),哪些是被其他对象共享的(比如已导入的模块,不会被回收)。

可行方案

1. 使用tracemalloc追踪内存变化

这是最直接的无侵入方案,不依赖对象实现细节,不管是纯Python类还是C扩展对象都适用:

import tracemalloc
import gc

# 启动内存追踪
tracemalloc.start()

# 记录对象创建前的内存快照
snapshot_before = tracemalloc.take_snapshot()

# 创建目标对象(比如你的自定义LRU缓存容器)
target_obj = YourCustomLRUContainer()
# 填充缓存数据...

# 记录对象创建后的内存快照
snapshot_after_create = tracemalloc.take_snapshot()

# 删除对象并触发强制垃圾回收
del target_obj
gc.collect()

# 记录回收后的内存快照
snapshot_after_delete = tracemalloc.take_snapshot()

# 计算实际释放的内存
create_stats = snapshot_after_create.compare_to(snapshot_before, 'lineno')
delete_stats = snapshot_after_delete.compare_to(snapshot_after_create, 'lineno')
released = sum(stat.size_diff for stat in create_stats) + sum(stat.size_diff for stat in delete_stats)

print(f"实际释放内存: {released / 1024 / 1024:.2f} MB")

这种方法会自动忽略已存在的共享对象(比如已导入模块),只统计因当前对象创建/删除产生的内存变化。

2. 自定义容器:暴露缓存内存统计接口

如果是你自己实现的类dict容器(带LRU缓存),可以直接在类中添加方法,只统计缓存内的对象大小:

import sys

class CustomLRUContainer:
    def __init__(self):
        self.cache = {}  # LRU缓存的核心存储
        # 其他文件读取逻辑...
    
    def get_cache_memory_usage(self):
        total = sys.getsizeof(self.cache)
        # 累加缓存内所有键值对的大小
        for k, v in self.cache.items():
            total += sys.getsizeof(k)
            total += sys.getsizeof(v)
        return total

这种方式精准控制统计范围,只计算缓存部分,不会涉及文件中的未加载数据。

3. 基于引用计数的递归统计(仅适用于纯Python对象)

对于纯Python对象,可以通过gc.get_referents()递归获取对象的直接引用,再筛选出引用计数为1的对象(这些对象会随目标对象被回收),累加它们的大小:

import sys
import gc

def get_releasable_size(obj):
    seen = set()
    total = 0

    def traverse(o):
        nonlocal total
        if id(o) in seen:
            return
        seen.add(id(o))
        # 仅统计引用计数为1的对象(仅被当前对象链引用)
        if sys.getrefcount(o) == 1:
            total += sys.getsizeof(o)
        # 递归处理直接引用的对象
        for referent in gc.get_referents(o):
            if isinstance(referent, (list, dict, tuple, set)):
                traverse(referent)
    
    traverse(obj)
    return total

注意:这种方法对C扩展对象无效,因为C扩展可能不参与Python的引用计数追踪。

关键注意事项

  • 共享对象(如已导入模块、全局变量)即使被目标对象持有,删除后也不会被回收,tracemalloc会自动排除这部分内存。
  • 若对象是C实现的扩展,只要遵循Python内存管理规范(使用Py_INCREF/Py_DECREF),tracemalloc就能正常追踪;如果是独立的C内存池,需要在扩展中添加自定义的内存统计接口。

细化问题的方向指引

如果需求仍不清晰,可以从以下维度明确:

  • 对象的内存管理类型:纯Python对象、Python+C扩展,还是独立的C++内存池?
  • 统计场景:实时统计,还是离线快照对比?
  • 精度要求:是否需要精确到字节,还是只需量级估算?

内容的提问来源于stack exchange,提问作者Liming Xu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:26:18