从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 相关文章推荐
压缩包密码破解示例分享(类似典破解)
Jan 17 Python
Python 正则表达式入门(初级篇)
Dec 07 Python
Python实现字典按照value进行排序的方法分析
Dec 23 Python
python递归函数绘制分形树的方法
Jun 22 Python
Python中的groupby分组功能的实例代码
Jul 11 Python
深入flask之异步非堵塞实现代码示例
Jul 31 Python
Python对ElasticSearch获取数据及操作
Apr 24 Python
python多进程并行代码实例
Sep 30 Python
Python如何优雅获取本机IP方法
Nov 10 Python
Pytorch中Tensor与各种图像格式的相互转化详解
Dec 26 Python
tensorboard显示空白的解决
Feb 15 Python
Windows下Anaconda和PyCharm的安装与使用详解
Apr 23 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
别人整理的服务器变量:$_SERVER
2006/10/20 PHP
从零开始学YII2框架(三)扩展插件yii2-gird
2014/08/20 PHP
php的4种常见运行方式
2015/03/20 PHP
PHP实现根据密码长度显示安全条
2017/07/04 PHP
php基于session锁防止阻塞请求的方法分析
2017/08/07 PHP
详解PHP如何更好的利用PHPstorm的自动提示
2017/08/18 PHP
PHP pthreads v3下的Volatile简介与使用方法示例
2020/02/21 PHP
showModelessDialog()使用详解
2006/09/21 Javascript
用于判断用户注册时,密码强度的JS代码
2009/01/01 Javascript
捕获关闭窗口的脚本
2009/01/10 Javascript
浅谈javascript中的作用域
2012/04/07 Javascript
javascript+xml实现简单图片轮换(只支持IE)
2012/12/23 Javascript
JavaScript判断密码强度(自写代码)
2013/09/06 Javascript
当达到输入长度时表单自动切换焦点
2014/04/06 Javascript
javascript实现table表格隔行变色的方法
2015/05/13 Javascript
javascript实现仿腾讯游戏选择
2015/05/14 Javascript
举例详解JavaScript中Promise的使用
2015/06/24 Javascript
超赞的jQuery图片滑块动画特效代码汇总
2016/01/25 Javascript
javascript实现查找数组中最大值方法汇总
2016/02/13 Javascript
JavaScript仿聊天室聊天记录
2016/12/27 Javascript
vue-router跳转页面的方法
2017/02/09 Javascript
利用node.js实现自动生成前端项目组件的方法详解
2017/07/12 Javascript
详解vue-cli与webpack结合如何处理静态资源
2017/09/19 Javascript
微信小程序 如何引入外部字体库iconfont的图标
2018/01/31 Javascript
小程序开发中如何使用async-await并封装公共异步请求的方法
2019/01/20 Javascript
[50:27]OG vs LGD 2018国际邀请赛淘汰赛BO3 第一场 8.26
2018/08/30 DOTA
跟老齐学Python之眼花缭乱的运算符
2014/09/14 Python
理解Python中的绝对路径和相对路径
2017/08/30 Python
Python UnboundLocalError和NameError错误根源案例解析
2018/10/31 Python
Pandas Shift函数的基础入门学习笔记
2018/11/16 Python
Python GUI自动化实现绕过验证码登录
2020/01/10 Python
python raise的基本使用
2020/09/10 Python
德国运动鞋网上商店:Afew Store
2018/01/05 全球购物
员工生日活动方案
2014/08/24 职场文书
运动会加油稿
2015/07/22 职场文书
小学英语课教学反思
2016/02/15 职场文书