python源码剖析-笔记1

  1. python中的所有东西都是对象,是在堆上申请的结构体。除了类型对象(type object),所有的对象都不能被静态初始化。
    1. 静态初始化。静态变量的初始化可分为编译期初始化、加载时初始化和运行时初始化。基本数据类型的在编译期即可完成初始化,对于类等复杂类型的需要在程序加载时初始化,对于在局部作用于内的静态对象,则需要在第一次运行时被初始化。
  2. python对象的大小一旦创建便是固定的,如果要有可变长的,是其内部一个指针指向一个可变长内存区域块。
  3. 每个python object的头部都是一样的,如此一个object*的指针可以指向任意的对象。
  4. 他们的头部都有一个ob_refcnt整形,用于引用计数。ob_size是可变长对象中的一个值,指包含可变对象的个数,如list的实现便是。
  5. 头部有一个_typeobject的对象指针,这个对象是用来标记这个类的具体类型,这个类里面包含了这个类型对象的空间大小等数据,内存开辟具体空间时会采用到这个对象内的数据。
  6. 那么类型对象怎么标识它的类型呢?PyTypeObject
  7. 多态正是基于ob_type来实现,object->ob_type->tp_print(object)。相应的通用操作接口封装在TypeObject类中。诸如对象的析构、打印都有一层在TypeObject类中的接口封装。
  8. python对象采用引用计数进行内存空间的管理与垃圾回收,Py_INCREF(op)和Py_DECREF(op)两个宏分别增加和减少一个引用计数值,当引用计数变为0时,py_DECREF会通过ob_type的析构接口来释放对应的对象资源。
    1. 类型对象的引用不会增加计数
  9. 为了避免频繁的malloc/free,python大都采用了内存池
    1. 比如小整数,for遍历时会经常用到,这里都是用的内存池来管理,内存池的个数大小可以修改NSMALLPOSINTS这些值,然后重新编译下python代码即可自定义扩展缩放这个池子的大小。
    2. 其他整数,python维护这一块内存空间由大整数们轮流使用。基于PyIntBlock结构实现了一个单向链表,链表由block_list指向,具体的obj由free_list指向,而内部每个obj通过ob_type进行链接。
  10. PyIntObject类里面加法实现判断是否溢出采用了位运算
    1. if ((a^c) < 0 && (b^c) < 0)则一定溢出,原因是异或操作,结果c和运算操作数a、b的符号都不同了,那么肯定就是溢出了
  11. 简单来说,整数内存池就是维护了一堆的block,每个block里面又有一个链表的结构来组织分配的内存。free_list指向实际可用的内存,一个block用完后再开一个block,然后把这些block全部链接起来。所有blcok里面的空闲内存实际都是链接在一起的,链接的表头就是free_list,如此可以保证一旦前面的blcok有内存腾出来,下次分配时便可以直接使用到。这些空闲内存的链接工作都在PyIntObj对象被释放的时候来完成。
  12. 对于同一个大点的整数,比如-123456,两个都是这个值得整数,实际上是两个不同的对象,地址是不同的!但是对于小整数来说,是同一个内存地址,但是对应的小整数对象的引用计数值会增加!
发布了47 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/it_wjw/article/details/93617368