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

Python内存dump:基于id地址定位变量及区分栈堆边界

Python内存定位与栈堆边界解析

一、通过id()返回的地址定位变量

Python中id()返回的是对象在内存中的起始地址(CPython实现下),要在内存dump中定位到对应对象,可按以下步骤操作:

    1. 地址转换:把id()输出的十进制地址转为十六进制(比如id(a)=140706166402816转成0x7FF9C555A000),这是对象结构体的起始位置。
    1. 识别对象头部:CPython所有对象都以PyObject结构体开头,64位系统下结构为:
    typedef struct _PyObject {
        _PyObject_HEAD_EXTRA  // GC用双向链表指针,占16字节
        Py_ssize_t ob_refcnt; // 引用计数,8字节
        struct _typeobject *ob_type; // 类型指针,8字节
    } PyObject;
    
    在dump中定位到目标地址后,查看ob_type指针值,可对应到PyLong_Type(整数类型)的地址,以此验证是否为目标整数对象;后续字节则是对象的实际值(小整数直接存在结构体特定字段,大整数用数组存储)。
    1. 关联变量名:变量名(a/b/c)并非直接存在堆对象中,而是存储在当前栈帧的局部变量表里。栈帧位于系统栈中,局部变量表是栈帧内的指针数组,每个元素指向对应对象的地址(即id()返回值)。你可以通过进程内存映射找到栈区域,再在栈帧结构中定位f_localsplus数组,匹配其中的指针与对象地址,结合栈帧中co_varnames元组(存储变量名)完成变量名与对象的关联。

二、区分栈与堆的边界

在CPython中,栈和堆的分工与边界可通过以下方式识别:

  • 栈区域:
    • 存储内容:Python解释器的栈帧(含局部变量表、指令指针、返回地址)、C层函数调用的栈数据。
    • 内存特征:在Linux/proc/[pid]/maps中标记为stack,地址从高到低增长,由系统自动管理生命周期。
  • 堆区域:
    • 存储内容:所有Python对象(整数、列表、字典等),由Python内存分配器(基于arena池机制,并非直接调用系统malloc)管理。
    • 内存特征:在/proc/[pid]/maps中标记为heap或anon_inode:[python_mmap](Python内存池区域),地址从低到高增长,对象生命周期由GC和引用计数控制。
  • 边界验证:将id()返回的地址与/proc/[pid]/maps中的区域对比,即可判断对象属于栈还是堆。比如小整数(如你的代码中5、2)属于Python预缓存的对象,存放在只读内存区域;而动态计算出的对象(如c=a+b的结果)则存放在堆或内存池中。

三、列表与字典的测试提示

测试可变对象时,重点关注其结构体的指针数组:

  • 列表:PyListObject结构体包含ob_item指针数组,每个元素指向列表中元素的对象地址。打印lst = [1,2,3]的id(lst)及每个元素的id(),在dump中定位列表地址后,可找到ob_item数组,验证其中的指针是否与元素id()一致。
  • 字典:PyDictObject的哈希表存储键值对的指针,每个键和值都是独立的Python对象,可通过类似方法定位字典地址,查看哈希表中的指针关联键值对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 11:17:26