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

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

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的分析相符

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页