zoukankan      html  css  js  c++  java
  • 《垃圾回收的算法与实现》——Python垃圾回收

    Python垃圾回收

    python采用引用计数法进行垃圾回收

    Python内存分配

    • python在分配内存空间时,在malloc之上堆放了3个独立的分层。
    • python内存分配时主要由arena、pool和block三个构成。

    第0层

    • 该层指glibc的malloc()这样的分配器,是对OS申请内存的部分。
    • python中如果生成的对象大于256B直接调用malloc,否则直接通过第1、2层分配。

    第1层

    • 该层主要管理arena,arena大小固定为256KB,其中保存了arena中开头的pool的地址。
    • 同时保持被分配的pool的数量、将空pool连接到单向链表的功能。
    • arena是被数组arenas管理。
    • unused_arena_objects单向链表连接未使用的arena,包括新生的或使用过但已废弃的。
    • usable_arenas双链表,其中arena分配了可利用的pool。

    第2层

    • 该层主要管理pool中的block,大小固定为4KB,每个pool的开头地址按照4KB的倍数对齐,与OS的页重合。
    • 在arena中将各个pool相连接。
    • pool被分隔成一个个的block,在pool初始化时就决定了该pool内的block的大小,block的大小是8B的整数倍,最大不超过256B。
    • Python分配时使用Best-fit,分配的block的大小最接近申请大小。
    • usedpools是保持pool的数组,每个pool用双向链表相连,数组中第一个位置中的是8B的pool集合直到第32个位置中的256B的pool。
    • 当usedpools中的pool的所有block被释放给arena。
    • block包括已经分配、使用完毕和未使用三种状态,后两者均可以将对象分配进去。
    • pool中定义了freeblock空闲表,用于链接使用完毕的block,而未使用的则在pool开头的nextoffset记录已分配的偏移。

    分配

    • 根据申请的大小找到usedpools的索引。
    • 当usedpools中指定索引的pool被分配了则从pool中freeblock尝试获取block,不行则通过偏移取出block,如果pool内没有能分配的block则将pool从usedpools中移除。
    • 如果没有block则通过new_arena将新的arena添加到usable_arensa中,如果分配失败则调用malloc。
    • 初始化pool,从arena的freepools中获取一个pool插入到usedpools的开头,而后检查pool固定block大小与申请的block大小是否相同,如果不同则还需要初始化pool

    释放

    • 将释放对象的block连接到freeblock。
    • 当pool内无已经分配的pool则将该pool连接到arena的freepools同时从usedpools中移除。
    • 当arena为空,从usable_arena移除,连接到unused_arena_objects中。
    • 当arena只有一个空pool时,即之前所有pool均被使用此时释放了一个pool,因此需要加入到usable_arenas。
    • usable_arenas内按照空pool的数量从小到大进行排序。usedpools也是优先使用被利用最多的pool。

    对象特有的分配器

    • python中各种类型的对象持有各自的分配器。
    • 不同的对象拥有不同的空闲链表(数组),使用完毕的对象初始化后加入到该链表。
    • 如果空闲链表满了则直接释放。

    引用计数

    • 对象内部有个计数器,32位环境下为int型,64位环境下为long型,指针为4的倍数因此使用这个长度还能多出两位。

    循环引用垃圾回收

    • 对象链表(双向链表)连接各个对象,对象的引用计数器复制到自对象内的另一个位置。
    • 对复制的计数器中非根直接引用的减1。
    • 将对象分为可能到达的对象的链表,复制计数器大于1或有从活动对象的引用。
    • 将其余对象放如不可能到达的对象的链表,这些对象即是循环引用垃圾。
    • 容器对象:可能保留了指向其他对象的运用的对象
    • 循环引用的对象只可能出现在容器对象,可以将容器对象用对象链表连接。
    • 分代容器对象链表,分为3代,每代有个阈值,超过该阈值则进行该代的回收。同时每回收一次进行晋升一次。
  • 相关阅读:
    extjs4 tree 父子节点联级勾选,半选节点半透明处理
    回调函数设计及应用(Java)——分组模式设计
    未来发展方向
    博客园网摘chrome插件源码分析
    apue2 阅读笔记第11章
    apue2 阅读笔记第八章
    APUE阅读笔记第十五章(第一部分)
    一个常用的vimrc
    apue2 阅读笔记第12章
    APUE阅读笔记第十四章(第二部分)
  • 原文地址:https://www.cnblogs.com/suolu/p/6664210.html
Copyright © 2011-2022 走看看