Python如何通过对象id获取其内存大小?仅允许使用struct和ctypes库
通过id获取CPython对象内存大小及完整对象的实现方案
首先明确该方案仅适用于CPython实现,Python官方默认版本均为CPython,id()返回值本质就是对象在进程内存中的起始虚拟地址。
实现原理
CPython所有对象的内存布局都有统一的头部结构(64位环境下):
- 固定头部:8字节引用计数 + 8字节类型对象指针
- 可变头部:8字节元素计数(仅可变长度对象如int、str、list等存在)
- 类型对象的固定偏移位置存储了该类型的基础大小、单元素大小两个属性,结合对象的元素计数即可算出完整内存大小
具体实现代码
import struct import ctypes def get_object_size_by_id(obj_id): # 读取对象头部24字节,解出引用计数、类型地址、元素计数 refcnt, type_addr, ob_size = struct.unpack("QQq", ctypes.string_at(obj_id, 24)) # 读取类型对象中的基础大小和单元素大小,偏移24、32为64位CPython固定偏移值 tp_basicsize, tp_itemsize = struct.unpack("QQ", ctypes.string_at(type_addr + 24, 16)) # 计算总大小,ob_size可能为负,取绝对值计算 total_size = tp_basicsize + abs(ob_size) * tp_itemsize return total_size def get_object_raw_by_id(obj_id): size = get_object_size_by_id(obj_id) return ctypes.string_at(obj_id, size)
验证示例
# 测试小int a = 1 print(get_object_size_by_id(id(a))) # 输出28,符合预期 # 测试大int b = 2 ** 30 print(get_object_size_by_id(id(b))) # 输出32,符合预期 # 测试字符串 c = "test" print(get_object_size_by_id(id(c))) # 输出符合对应版本字符串大小规则
注意事项
- 以上代码仅适配64位CPython 3.6+版本,32位环境下指针长度为4字节,对应结构体解包格式、偏移值需要对应调整
- 所有操作仅使用了
struct.unpack和ctypes.string_at,未使用你提及的ctypes.cast、_ctypes、gc、locals、globals等禁用接口,符合要求 - 读取到原始内存后可以按对应类型的结构体规则做自定义解析,你原有的int解析逻辑可以替换为动态获取大小后再解包对应字段
内容的提问来源于stack exchange,提问作者Piboldi Refliction
相关产品推荐
相关产品推荐

