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

Python空类内存占用构成及sys.getsizeof与dir统计差异疑问

Python中空类、实例与空函数的内存占用分析

问题背景

我用Python 3.12.3编写了一段代码,对比空类、空类实例和空函数的内存占用:

import sys

class EmptyClass:
    pass

def empty_func():
    pass

print(f"Class size:        {sys.getsizeof(EmptyClass)}")
print(f"Instance size:     {sys.getsizeof(EmptyClass())}")
print(f"Function size:     {sys.getsizeof(empty_func)}")

# 统计对象属性的内存总和
def get_mem_size(obj):
    mem = 0
    for name in dir(obj):
        attr = getattr(obj, name)
        mem += sys.getsizeof(attr)
    return mem

print(f"Class dir size:    {get_mem_size(EmptyClass)}")
print(f"Function dir size: {get_mem_size(empty_func)}")

运行输出:

Class size:        1704
Instance size:     48
Function size:     160
Class dir size:    2185
Function dir size: 12287

我原本认为空类的内存占用应该等于其类变量和方法的总大小(通过dir(obj)统计),但实际sys.getsizeof(EmptyClass)结果为1704,而dir统计的内存足迹为2185,二者存在差异。另外我想了解Python中空类的内存由哪些组件构成,以及如何通过这些组件明确计算其内存占用。


核心解释与答案

1. 两种统计方式的差异本质

sys.getsizeof(obj)仅返回对象自身直接占用的内存,不包含它引用的其他对象的内存。而dir(obj)会列出对象的所有属性(包括从父类继承的),get_mem_size统计的是这些属性对象各自的内存总和——这些属性本身是独立的对象(比如类的__dict__、__module__字符串、继承的方法等),它们的内存不算在类对象自身的sys.getsizeof结果里。

举个直观例子:EmptyClass的__dict__是一个字典对象,sys.getsizeof(EmptyClass)只计算这个字典对象的指针大小,而get_mem_size会把整个字典的内存(包括字典内存储的内容)加进去,这直接导致了数值差异。

2. 空类的内存构成(Python 3.12)

空类EmptyClass作为type的实例,其内存主要由以下部分构成:

  • 基础对象头:所有Python对象共有的元数据,包括引用计数、类型指针等,64位系统上通常占16字节。
  • 类核心结构:
    • 指向父类(如object)的指针
    • 类名称字符串的指针
    • 类所属模块信息的指针
    • 类的__dict__指针(用于存储类变量和自定义方法)
    • 类的方法缓存(加速属性查找)
    • 类型相关的内部标记、标志位
  • 内部存储结构:用于支持描述符、继承链的额外空间,以及解释器为类对象预分配的缓存区。

3. 准确计算类的总内存占用

如果要统计类对象及其所有引用对象的总内存,sys.getsizeof无法满足需求,需要递归遍历对象的所有引用并累加:

import sys
from gc import get_referents

def get_total_size(obj):
    seen = set()
    def inner(obj):
        if id(obj) in seen:
            return 0
        seen.add(id(obj))
        size = sys.getsizeof(obj)
        # 递归统计所有引用对象的内存
        for referent in get_referents(obj):
            size += inner(referent)
        return size
    return inner(obj)

class EmptyClass:
    pass

print(f"EmptyClass 总内存占用: {get_total_size(EmptyClass)}")

这个函数会递归计算对象自身和所有直接/间接引用对象的内存总和,能更准确反映类的实际内存足迹。

补充说明

  • 空类实例的48字节:64位Python中,空实例的内存包含对象头+实例__dict__指针(无__slots__时),加上内存对齐字节,总大小为48字节。
  • 空函数的160字节:函数对象包含代码对象指针、名称指针、闭包信息、默认参数存储等基础结构,这些结构的总大小在Python 3.12中为160字节。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 16:15:16