从Python的源码来解析Python下的freeblock


Posted in Python onMay 11, 2015

1 引言

在python内存管理中,有一个block的概念。它比较类似于SGI次级空间配置器。
首先申请一块大的空间(4KB),然后把它切割成一小份(8, 16 一直到512)。
当有内存申请的请求时候,简单的流程是:根据大小找到对应的block,然后在freeblock 上给它一份。

2 问题

整个过程是一种比较自然的slab分配方式。但当我读到这段代码时,却感到疑惑:

static void* _PyObject_Malloc(void* ctx, size_t nbytes)
{
    ...
  pool->freeblock = (block*)pool + pool->nextoffset;

    pool->nextoffset += INDEX2SIZE(size);
    *(block **)(pool->freeblock) = NULL; // [1]
    ...
}

freeblock指向空闲的链表,为它赋值很好理解。但是为什么要加上代码1处那一句!
对C比较熟悉的童鞋很容易能看出它的作用,它在为*freeblock赋值为NULL。

但是为什么要这么做?
直到看到内存回收的代码:

static void _PyObject_Free(void* ctx, void*p)
{
  ...
  *(block**)p = lastfree = pool->freeblock;
  pool->freeblock = (block*)p;
  ...
}

回想一下SGI次级空间配置,它需要一个链表,指向block中可用的小块。因为这些快,是离散的,只有用指针才能索引它。
在SGI次级空间配置中,是用一个union,达到了节省空间的目的:有数据时,它存储着真正的数据;没有数据时,它就变成指向下一块可用内存的指针:

union __Obj {
  union __Obj* free_list_link;
  char client_data[];
};

这样一想,问题就变得很明显了。freeblock指向一个链表,链表的next域就由它自己来索引。
在_PyObject_Free中,内存p是要被回收的,它应该插在freeblock的链表头,freeblock被更新指向它。同时,p指向原来freeblock指向的内容,这是一个很简单的链表插入操作。
这样在遍历的时候,我们就可以用freeblock = * freeblock的方式来工作了。
如下图所示:

从Python的源码来解析Python下的freeblock

Python 相关文章推荐
使用 Python 获取 Linux 系统信息的代码
Jul 13 Python
最基础的Python的socket编程入门教程
Apr 23 Python
python爬虫入门教程--快速理解HTTP协议(一)
May 25 Python
Python结合ImageMagick实现多张图片合并为一个pdf文件的方法
Apr 24 Python
python生成多个只含0,1元素的随机数组或列表的实例
Nov 12 Python
python lambda表达式在sort函数中的使用详解
Aug 28 Python
Django后端发送小程序微信模板消息示例(服务通知)
Dec 17 Python
Python多线程threading创建及使用方法解析
Jun 17 Python
keras分类之二分类实例(Cat and dog)
Jul 09 Python
一篇文章教你用python画动态爱心表白
Nov 22 Python
从np.random.normal()到正态分布的拟合操作
Jun 02 Python
PYTHON 使用 Pandas 删除某列指定值所在的行
Apr 28 Python
详解Python的Django框架中的templates设置
May 11 #Python
Python素数检测的方法
May 11 #Python
Python中IPYTHON入门实例
May 11 #Python
Python使用MONGODB入门实例
May 11 #Python
python学习数据结构实例代码
May 11 #Python
Python使用CMD模块更优雅的运行脚本
May 11 #Python
Python中DJANGO简单测试实例
May 11 #Python
You might like
世界咖啡生产者论坛呼吁:需要立即就咖啡价格采取认真行动
2021/03/06 咖啡文化
网站加速 PHP 缓冲的免费实现方法
2006/10/09 PHP
在命令行下运行PHP脚本[带参数]的方法
2010/01/22 PHP
php数组函数序列之array_pop() - 删除数组中的最后一个元素
2011/11/07 PHP
ThinkPHP文件缓存类代码分享
2015/04/22 PHP
thinkPHP多域名情况下使用memcache方式共享session数据的实现方法
2016/07/21 PHP
JavaScript实现删除电脑的关机键
2016/07/26 PHP
PHP对称加密算法(DES/AES)类的实现代码
2017/11/14 PHP
php DES加密算法实例分析
2019/09/18 PHP
php-7.3.6 编译安装过程
2020/02/11 PHP
Javascript中的相等与不等运算
2010/04/25 Javascript
node.js中的buffer.Buffer.isEncoding方法使用说明
2014/12/14 Javascript
JavaScript中number转换成string介绍
2014/12/31 Javascript
ichart.js绘制虚线、平均分虚线效果的实现代码
2016/05/05 Javascript
详解jQuery选择器
2016/12/21 Javascript
JavaScript动态加载重复绑定问题
2018/04/01 Javascript
vue单页面实现当前页面刷新或跳转时提示保存
2018/11/02 Javascript
基于AngularJS拖拽插件ngDraggable.js实现拖拽排序功能
2019/04/02 Javascript
通过实例解析js简易模块加载器
2019/06/17 Javascript
[01:46]新英雄登场
2019/09/10 DOTA
Python查找相似单词的方法
2015/03/05 Python
Python匹配中文的正则表达式
2016/05/11 Python
详解python3实现的web端json通信协议
2016/12/29 Python
Python中最大递归深度值的探讨
2019/03/05 Python
python实现五子棋人机对战游戏
2020/03/25 Python
解决echarts中饼图标签重叠的问题
2020/05/16 Python
python 基于PYMYSQL使用MYSQL数据库
2020/12/24 Python
KIKO MILANO荷兰网上商店:意大利专业化妆品品牌
2017/05/12 全球购物
Farfetch阿联酋:奢侈品牌时尚购物平台
2019/07/26 全球购物
校庆筹备方案
2014/03/30 职场文书
临时工聘用合同协议书
2014/10/29 职场文书
党员民主生活会材料
2014/12/15 职场文书
家长会后的感想
2015/08/11 职场文书
读《庄子》有感:美而不自知
2019/11/06 职场文书
导游词之苏州盘门景区
2019/11/12 职场文书
Python Numpy库的超详细教程
2022/04/06 Python