从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系列之新版本导入httplib模块报ImportError解决方案
May 23 Python
Python的Django框架可适配的各种数据库介绍
Jul 15 Python
Python爬虫实现爬取京东手机页面的图片(实例代码)
Nov 30 Python
Python简单读写Xls格式文档的方法示例
Aug 17 Python
python实现换位加密算法的示例
Oct 14 Python
对python中的乘法dot和对应分量相乘multiply详解
Nov 14 Python
Python3调用百度AI识别图片中的文字功能示例【测试可用】
Mar 13 Python
pytorch 使用加载训练好的模型做inference
Feb 20 Python
python GUI库图形界面开发之PyQt5控件QTableWidget详细使用方法与属性
Feb 25 Python
Python3 操作 MySQL 插入一条数据并返回主键 id的实例
Mar 02 Python
python将数据插入数据库的代码分享
Aug 16 Python
如何在Anaconda中打开python自带idle
Sep 21 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
php文档更新介绍
2011/07/22 PHP
php写入、删除与复制文件的方法
2015/06/20 PHP
PHP封装返回Ajax字符串和JSON数组的方法
2017/02/17 PHP
php取出数组单个值的方法
2018/03/12 PHP
jQuery 性能优化指南(3)
2009/05/21 Javascript
实现png图片和png背景透明(支持多浏览器)的方法
2009/09/08 Javascript
获取服务器传来的数据 用JS去空格的正则表达式
2012/03/26 Javascript
JavaScript+CSS实现仿Mootools竖排弹性动画菜单效果
2015/10/14 Javascript
Bootstrap实现默认导航栏效果
2020/09/21 Javascript
67 个节约开发时间的前端开发者的工具、库和资源
2017/09/12 Javascript
VueJs 将接口用webpack代理到本地的方法
2017/11/27 Javascript
微信小程序基于本地缓存实现点赞功能的方法
2017/12/18 Javascript
利用js给datalist或select动态添加option选项的方法
2018/01/25 Javascript
使用Angular CLI进行单元测试和E2E测试的方法
2018/03/24 Javascript
微信小程序中使用echarts的实现方法
2019/04/24 Javascript
vue实现导航标题栏随页面滚动渐隐渐显效果
2020/03/12 Javascript
python实现将元祖转换成数组的方法
2015/05/04 Python
剖析Python的Tornado框架中session支持的实现代码
2015/08/21 Python
pycharm运行和调试不显示结果的解决方法
2018/11/30 Python
python+selenium实现QQ邮箱自动发送功能
2019/01/23 Python
python如何统计代码运行的时长
2019/07/24 Python
python对常见数据类型的遍历解析
2019/08/27 Python
python聚类算法解决方案(rest接口/mpp数据库/json数据/下载图片及数据)
2019/08/28 Python
python自动化测试无法启动谷歌浏览器问题
2019/10/10 Python
opencv设置采集视频分辨率方式
2019/12/10 Python
python excel多行合并的方法
2020/12/09 Python
购买瑞典当代设计的腕表和太阳眼镜:TRIWA
2016/10/30 全球购物
澳大利亚领先的女帽及配饰公司:Morgan&Taylor
2019/12/01 全球购物
机电一体化自荐信
2013/12/10 职场文书
《风筝》教学反思
2014/04/10 职场文书
司机个人年终总结
2015/03/03 职场文书
2019 入党申请书范文
2019/07/10 职场文书
超外差式晶体管收音机的组装与统调
2021/04/22 无线电
MySQL 角色(role)功能介绍
2021/04/24 MySQL
Python机器学习之PCA降维算法详解
2021/05/19 Python
vue route新窗口跳转页面并且携带与接收参数
2022/04/10 Vue.js