Python源码剖析[5] —— 整数对象(3)

    技术2022-05-11  116

    [绝对原创 转载请注明出处]

    Python源码剖析

    ——整数对象PyIntObject(3)

    本文作者: Robert Chen (search.pythoner@gmail.com)

    3         Hack PyIntObject

    现在,让我们荡起双桨,哦不对,让我们挽起衣袖和裤脚J,来和PyIntObject大战一场。我们渴望在运行时观察Python的整数对象体系的变化。这一点,完全可以通过修改Python源码来实现。我们修改了int_print的行为,让它打印出关于block_listfree_list的信息,以及小整数缓冲池的信息:

    static int int_print(PyIntObject *v, FILE *fp, int flags)

    {

       PyIntObject* intObjectPtr;

       PyIntBlock *p = block_list;

       PyIntBlock *last = NULL;

       int count = 0;

       int i;

     

     

       while(p != NULL)

       {

          ++count;

          last = p;

          p = p->next;

       }

     

     

       intObjectPtr = last->objects;

       intObjectPtr += N_INTOBJECTS - 1;

       printf("address @%p/n", v);

       printf("********** value/trefCount **********/n");

       for(i = 0; i < 10; ++i, --intObjectPtr)

       {

          printf("%d/t/t%d/n", intObjectPtr->ob_ival, intObjectPtr->ob_refcnt);

       }

     

     

       printf("block_list count : %d/n", count);

       printf("free_list : %p/n/n", free_list);

     

     

       return 0;

    }

    需要特别注意的是,在初始化小整数缓冲池时,对于block_list以及每个PyIntBlockobjects,都是从后往前开始填充的,所以在初始化完成后,-5应该在最后一个PyIntBlock对象的objects内最后一块内存,所以我们需要顺藤摸瓜,一直找到这最后的一块内存,才能观察从-5410个小整数。

    首先我们创建一个PyIntObject对象-9999,从图10所示的输出信息可以看到,小整数对象很多都被Python自身使用多次了。

    现在的free_list指向地址为00B6AF9C的内存,根据上面对PyIntObject的分析,那么下一个PyIntObject会在这个地址安身立命。那么好,我们接着再建立了两个PyIntObject对象,它们的值分别是-123456

    从图11所示的结果中可以看到a的地址正是创建ifree_list所指的地址,而b的地址也正是创建afree_list所指的地址。虽然ab的值都是一样的,但是它们确实是两个完全没有关系的PyIntObject对象,这点从地址上看得一清二楚。

    现在我们将b删除,结果如图12所示:

    删除b后,free_list回退到了a创建后free_list的位置,这一点也跟前面的分析是一致的。

    最后我们来看一看对小整数对象的监控,连续两次创建PyIntObject对象-5,结果如图13所示:

    可以看到,两次创建的PyIntObject对象d1d2的地址都是一样的,这证明它们实际上是同一个对象。同时,我们看到小整数池中-5的引用计数发生了变化,这证明d1d2实际上都是指向这个对象。此外,free_list没有发生任何变化。这些都与我们对PyIntObject的分析相符


    最新回复(0)