pythonpython的内存管理机制制求教

python的内存管理机制_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
python的内存管理机制
&&python的内存管理机制
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩2页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢Python 整数对象实现原理 - 我的成长之路 http://foofish.net - ITeye博客
博客分类:
整数对象在Python内部用PyIntObject结构体表示:
typedef struct {
PyObject_HEAD
PyObject_HEAD宏中定义的两个属性分别是:
struct _typeobject *ob_
这两个属性是所有Python对象固有的:
ob_refcnt:对象的引用计数,与Python的内存管理机制有关,它实现了基于引用计数的垃圾收集机制
ob_type:用于描述Python对象的类型信息。
由此看来PyIntObject就是一个对C语言中long类型的数值的扩展,出于性能考虑,对于小整数,Python使用小整数对象池small_ints缓存了[-5,257)之间的整数,该范围内的整数在Python系统中是共享的。
#define NSMALLPOSINTS
#define NSMALLNEGINTS
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
而超过该范围的整数即使值相同,但对象不一定是同一个,如下所示:当a与b的值都是10000,但并不是同一个对象,而值为1的时候,a和b属于同一个对象。
&&& a = 10000
&&& b = 10000
&&& print a is b
&&& print a is b
对于超出了[-5, 257)之间的其他整数,Python同样提供了专门的缓冲池,供这些所谓的大整数使用,避免每次使用的时候都要不断的malloc分配内存带来的效率损耗。这块内存空间就是PyIntBlock。
struct _intblock {
struct _intblock *
PyIntObject objects[N_INTOBJECTS];
typedef struct _intblock PyIntB
static PyIntBlock *block_list = NULL;
static PyIntObject *free_list = NULL;
这些内存块(blocks)由一个单向链表表示,表头是block_list,block_list始终指向最新创建的PyIntBlock对象。next指针指向下一个PyIntBlock对象,objects是一个PyIntObject数组(最终会转变成单向链表),它是真正用于存储被缓存的PyIntObjet对象的内存空间。 free_list单向链表是所有block的objects中空闲的内存。所有空闲内存通过一个链表组织起来的好处就是在Python需要新的内存来存储新的PyIntObject对象时,能够通过free_list快速获得所需的内存。
创建一个整数对象时,如果它在小整数范围内,就直接从小整数缓冲池中直接返回,如果不在该范围内,就开辟一个大整数缓冲池内存空间:
[intobject.c]
PyObject* PyInt_FromLong(long ival)
register PyIntObject *v;
#if NSMALLNEGINTS + NSMALLPOSINTS & 0
//[1] :尝试使用小整数对象池
if (-NSMALLNEGINTS &= ival && ival & NSMALLPOSINTS) {
v = small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);
return (PyObject *)
//[2] :为通用整数对象池申请新的内存空间
if (free_list == NULL) {
if ((free_list = fill_free_list()) == NULL)
return NULL;
//[3] : (inline)内联PyObject_New的行为
free_list = (PyIntObject *)v-&ob_
PyObject_INIT(v, &PyInt_Type);
v-&ob_ival =
return (PyObject *)
fill_free_list就是创建大整数缓冲池内存空间的逻辑,该函数返回一个free_list链表,当整数对象ival创建成功后,free_list表头就指向了v-&ob_type,ob_type不是所有Python对象中表示类型信息的字段吗?怎么在这里作为一个连接指针呢?这是Python在性能与代码优雅之间取中庸之道,对名称的滥用,放弃了对类型安全的坚持。把它理解成指向下一个PyIntObject的指针即可。
[intobject.c]
static PyIntObject* fill_free_list(void)
PyIntObject *p, *q;
// 申请大小为sizeof(PyIntBlock)的内存空间
// block list始终指向最新创建的PyIntBlock
p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock));
((PyIntBlock *)p)-&next = block_
block_list = (PyIntBlock *)p;
//:将PyIntBlock中的PyIntObject数组(objects)转变成单向链表
p = &((PyIntBlock *)p)-&objects[0];
q = p + N_INTOBJECTS;
while (--q & p)
// ob_type指向下一个未被使用的PyIntObject。
q-&ob_type = (struct _typeobject *)(q-1);
q-&ob_type = NULL;
return p + N_INTOBJECTS - 1;
不同的PyIntBlock里面的空闲的内存是怎样连接起来构成free_list的呢?这个秘密放在了整数对象垃圾回收的时候,在PyIntObject对象的tp_dealloc操作中可以看到:
[intobject.c]
static void int_dealloc(PyIntObject *v)
if (PyInt_CheckExact(v)) {
v-&ob_type = (struct _typeobject *)free_
free_list =
v-&ob_type-&tp_free((PyObject *)v);
原来PyIntObject对象销毁时,它所占用的内存并不会释放,而是继续被Python使用,进而将free_list表头指向了这个要被销毁的对象上。
Python中的int对象就是c语言中long类型数值的扩展
小整数对象[-5, 257]在python中是共享的
整数对象都是从缓冲池中获取的。
整数对象回收时,内存并不会归还给系统,而是将其对象的ob_type指向free_list,供新创建的整数对象使用
lantian_123
浏览: 903354 次
来自: 广州
学会了recording,感谢~~
看完了才发现这篇文章果然是你写的
看完了,才发现时部长写的,真爱啊5.窗口对象本身被销毁:delmyList,或者;1、当内存中有不再使用的部分时,垃圾收集器就会把;2、垃圾回收机制还有一个循环垃圾回收器,确保释放;[1]Python2.7.8documentat;
5.窗口对象本身被销毁:del myList,或者窗口对象本身离开了作用域。
垃圾回收 1、当内存中有不再使用的部分时,垃圾收集器就会把他们清理掉。它会去检查那些引用计数为0的对象,然后清除其在内存的空间。当然除了引用计数为0的会被清除,还有一种情况也会被垃圾收集器清掉:当两个对象相互引用时,他们本身其他的引用已经为0了。 2、垃圾回收机制还有一个循环垃圾回收器, 确保释放循环引用对象(a引用b, b引用a, 导致其引用计数永远不为0)。
参考: [1] Python 2.7.8 documentation memory management [2]深入详解python传值问题及内存管理机制-CSDN [3]Python内存池管理与缓冲池设计 - 张知临的专栏 [4]理解python变量和内存管理
三亿文库包含各类专业文献、行业资料、各类资格考试、专业论文、生活休闲娱乐、文学作品欣赏、python的内存管理机制98等内容。 
 (C )B A、x = y = z = 1 B、x = (y = z + 1) C、x, y = y, x D、x += y 2.关于 Python 内存管理,下列说法错误的是 (B ) A、变量...  2.关于 Python 内存管理,下列说法错误的是 A、变量不必事先声明 B、变量无须先创建和赋值而直接使用 C、变量无须指定类型 D、可以使用 del 释放资源 ? 3、...  3 Python 是如何进行内存管理的? Python 提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。 Python 中所有小于 256 个字节的对象...  A、x = y = z = 1 C、x, y = y, x B、x = (y = z + 1) D、x += y ( b )(b) 2.关于 Python 内存管理,下列说法错误的是 A、变量...  Python 是基于值的内存管理方式,两个变量分别赋值为两个可变对象,值即 便相同,也会有两个可变对象存在。而对于不可变对象,由于其值不变,为 了性能方面的考虑,...  ● 内存采用段式存储管理有许多优点,但(1) 不是...超时 试题解析: 试题解析: 拥塞是无连接传输机制...C.python 9521 D.python 9976 试题解析: 试题解析...  2.2 引用计数 为了简化内存管理,Python 通过引用计数机制实现了自动的垃圾回收功能,Python 中的每个对象都有一个引用计数, 用来计数该对象在不同场所分别被引用了...  1.2 为什么说 Python 采用的是基于值的内存管理模式? Python 采用的是基于值...答: Python 支持字符串驻留机制,即:对于短字符串,将其赋值给多个不同的对象...  1.2 为什么说 Python 采用的是基于值的内存管理模式? 答: Python 采用的是...答: Python 支持字符串驻留机制,即:对于短字符串,将其赋值给多个不同的对象...博客访问: 568753
博文数量: 256
博客积分: 6891
博客等级: 准将
技术积分: 2497
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Python/Ruby
Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的
malloc。另外Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的
整数,用于缓存这些整数的内存就不能再分配给浮点数。
在Python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,由于这些内存的申请并不是为了创建对象,所以并没有对象一
级的内存池机制。这就意味着Python在运行期间会大量地执行malloc和free的操作,频繁地在用户态和核心态之间进行切换,这将严重影响
Python的执行效率。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。这也就是之前提到的
Pymalloc机制。
阅读(2407) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。Python源码阅读-内存管理机制(一) - Python - 伯乐在线
& Python源码阅读-内存管理机制(一)
==========================&
基本阅读完了, 只是没时间梳理, 趁着这今天时间比较空
逐步梳理, 发上来……也算是小结下, 要开始准备简历找工作了&_
这篇略长, 带很多图, 所以一分为二
Python的内存管理架构
在Objects/obmalloc.c源码中, 给了一个分层划分
[ int ] [ dict ] [ list ] ... [ string ]
Python core
+3 | &----- Object-specific memory -----& | &-- Non-object memory --& |
_______________________________
Python's object allocator
+2 | ####### Object memory ####### | &------ Internal buffers ------& |
______________________________________________________________
Python's raw memory allocator (PyMem_ API)
+1 | &----- Python memory (under PyMem manager's control) ------& |
__________________________________________________________________
Underlying general-purpose allocator (ex: C library malloc)
0 | &------ Virtual memory allocated for the python process -------& |
=========================================================================
_______________________________________________________________________
OS-specific Virtual Memory Manager (VMM)
-1 | &--- Kernel dynamic storage allocation & management (page-based) ---& |
__________________________________
__________________________________
-2 | &-- Physical memory: ROM/RAM --& | | &-- Secondary storage (swap) --& |
1234567891011121314151617181920
&&&&_____&& ______&& ______&&&&&& ________&& [ int ] [ dict ] [ list ] ... [ string ]&&&&&& Python core&&&&&&&& |+3 | &----- Object-specific memory -----& | &-- Non-object memory --& |&&&&_______________________________&&&&&& |&&&&&&&&&&&&&&&&&&&&&&&&&& |&& [&& Python's object allocator&& ]&&&&&&|&&&&&&&&&&&&&&&&&&&&&&&&&& |+2 | ####### Object memory ####### | &------ Internal buffers ------& |&&&&______________________________________________________________&&&&|&& [&&&&&&&&&&Python's raw memory allocator (PyMem_ API)&&&&&&&&&&]&& |+1 | &----- Python memory (under PyMem manager's control) ------& |&& |&&&&__________________________________________________________________&& [&&&&Underlying general-purpose allocator (ex: C library malloc)&& ] 0 | &------ Virtual memory allocated for the python process -------& |&&& =========================================================================&&&&_______________________________________________________________________&& [&&&&&&&&&&&&&&&&OS-specific Virtual Memory Manager (VMM)&&&&&&&&&&&&&& ]-1 | &--- Kernel dynamic storage allocation & management (page-based) ---& |&&&&__________________________________&& __________________________________&& [&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&] [&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&]-2 | &-- Physical memory: ROM/RAM --& | | &-- Secondary storage (swap) --& |
layer 3: Object-specific memory(int/dict/list/string....)
Python 实现并维护
更高抽象层次的内存管理策略, 主要是各类特定对象的缓冲池机制. 具体见前面几篇涉及的内存分配机制
layer 2: Python's object allocator
Python 实现并维护
实现了创建/销毁Python对象的接口(PyObject_New/Del), 涉及对象参数/引用计数等
layer 1: Python's raw memory allocator (PyMem_ API)
Python 实现并维护, 包装了第0层的内存管理接口, 提供统一的raw memory管理接口
封装的原因: 不同操作系统 C 行为不一定一致, 保证可移植性, 相同语义相同行为
layer 0: Underlying general-purpose allocator (ex: C library malloc)
操作系统提供的内存管理接口, 由操作系统实现并管理, Python不能干涉这一层的行为
1234567891011121314
layer 3: Object-specific memory(int/dict/list/string....)&&&&&&&& Python 实现并维护&&&&&&&& 更高抽象层次的内存管理策略, 主要是各类特定对象的缓冲池机制. 具体见前面几篇涉及的内存分配机制&layer 2: Python's object allocator&&&&&&&& Python 实现并维护&&&&&&&& 实现了创建/销毁Python对象的接口(PyObject_New/Del), 涉及对象参数/引用计数等&layer 1: Python's raw memory allocator (PyMem_ API)&&&&&&&& Python 实现并维护, 包装了第0层的内存管理接口, 提供统一的raw memory管理接口&&&&&&&& 封装的原因: 不同操作系统 C 行为不一定一致, 保证可移植性, 相同语义相同行为&layer 0: Underlying general-purpose allocator (ex: C library malloc)&&&&&&&& 操作系统提供的内存管理接口, 由操作系统实现并管理, Python不能干涉这一层的行为
第三层layer 3前面已经介绍过了, 几乎每种常用的数据类型都伴有一套缓冲池机制.
在这里, 我们关注的是layer 2/1
简要介绍下layer 1, 然后重点关注layer 2, 这才是重点
layer 1: PyMem_ API
PyMem_ API是对操作系统内存管理接口进行的封装
查看pymem.h可以看到
// Raw memory interface
// 这里存在三个宏定义, 宏可以避免一次函数调用的开销, 提高运行效率
// 不允许非配空间大小为0的内存空间
#define PyMem_MALLOC(n)
((size_t)(n) & (size_t)PY_SSIZE_T_MAX ? NULL
: malloc((n) ? (n) : 1))
#define PyMem_REALLOC(p, n) ((size_t)(n) & (size_t)PY_SSIZE_T_MAX
: realloc((p), (n) ? (n) : 1))
#define PyMem_FREE
// 这里做了三个函数的声明, 平台独立的 malloc/realloc/free
PyAPI_FUNC(void *) PyMem_Malloc(size_t);
PyAPI_FUNC(void *) PyMem_Realloc(void *, size_t);
PyAPI_FUNC(void) PyMem_Free(void *);
// ============================================================
// Type-oriented memory interface
// 这里还有三个类型相关的内存接口, 批量分配/重分配 n 个 类型为 type内存
#define PyMem_New(type, n)
( ((size_t)(n) & PY_SSIZE_T_MAX / sizeof(type)) ? NULL :
( (type *) PyMem_Malloc((n) * sizeof(type)) ) )
#define PyMem_NEW(type, n)
( ((size_t)(n) & PY_SSIZE_T_MAX / sizeof(type)) ? NULL :
( (type *) PyMem_MALLOC((n) * sizeof(type)) ) )
#define PyMem_Resize(p, type, n)
( (p) = ((size_t)(n) & PY_SSIZE_T_MAX / sizeof(type)) ? NULL :
(type *) PyMem_Realloc((p), (n) * sizeof(type)) )
#define PyMem_RESIZE(p, type, n)
( (p) = ((size_t)(n) & PY_SSIZE_T_MAX / sizeof(type)) ? NULL :
(type *) PyMem_REALLOC((p), (n) * sizeof(type)) )
1234567891011121314151617181920212223242526272829303132
// Raw memory interface// 这里存在三个宏定义, 宏可以避免一次函数调用的开销, 提高运行效率// 不允许非配空间大小为0的内存空间#define PyMem_MALLOC(n)&&&& ((size_t)(n) & (size_t)PY_SSIZE_T_MAX ? NULL &&&&&&&&&&&&&&&&: malloc((n) ? (n) : 1))&#define PyMem_REALLOC(p, n) ((size_t)(n) & (size_t)PY_SSIZE_T_MAX&&? NULL &&&&&&&&&&&&&&&&: realloc((p), (n) ? (n) : 1))#define PyMem_FREE&&&&&&free&// 这里做了三个函数的声明, 平台独立的 malloc/realloc/freePyAPI_FUNC(void *) PyMem_Malloc(size_t);PyAPI_FUNC(void *) PyMem_Realloc(void *, size_t);PyAPI_FUNC(void) PyMem_Free(void *);&// ============================================================&// Type-oriented memory interface// 这里还有三个类型相关的内存接口, 批量分配/重分配 n 个 类型为 type内存#define PyMem_New(type, n) &&( ((size_t)(n) & PY_SSIZE_T_MAX / sizeof(type)) ? NULL :&&&&&&( (type *) PyMem_Malloc((n) * sizeof(type)) ) )#define PyMem_NEW(type, n) &&( ((size_t)(n) & PY_SSIZE_T_MAX / sizeof(type)) ? NULL :&&&&&&( (type *) PyMem_MALLOC((n) * sizeof(type)) ) )&#define PyMem_Resize(p, type, n) &&( (p) = ((size_t)(n) & PY_SSIZE_T_MAX / sizeof(type)) ? NULL :&&&&&&&&(type *) PyMem_Realloc((p), (n) * sizeof(type)) )#define PyMem_RESIZE(p, type, n) &&( (p) = ((size_t)(n) & PY_SSIZE_T_MAX / sizeof(type)) ? NULL :&&&&&&&&(type *) PyMem_REALLOC((p), (n) * sizeof(type)) )
然后object.c中, 我们关注实现, 三个实现的函数调用了对应的宏
// 使用 C 写Python扩展模块时使用函数而不是对应的宏
PyMem_Malloc(size_t nbytes)
return PyMem_MALLOC(nbytes);
PyMem_Realloc(void *p, size_t nbytes)
return PyMem_REALLOC(p, nbytes);
PyMem_Free(void *p)
PyMem_FREE(p);
123456789101112131415161718
// 使用 C 写Python扩展模块时使用函数而不是对应的宏void *PyMem_Malloc(size_t nbytes){&&&&return PyMem_MALLOC(nbytes);}&void *PyMem_Realloc(void *p, size_t nbytes){&&&&return PyMem_REALLOC(p, nbytes);}&voidPyMem_Free(void *p){&&&&PyMem_FREE(p);}
这些接口都相对简单
好了, 结束, 开始关注layer 2: Python's object allocator
Python 的内存分配策略
先来看Objects/obmalloc.c中的一段注释
* "Memory management is where the rubber meets the road -- if we do the wrong
* thing at any level, the results will not be good. And if we don't make the
* levels work well together, we are in serious trouble." (1)
* (1) Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles,
"Dynamic Storage Allocation: A Survey and Critical Review",
in Proc. 1995 Int'l. Workshop on Memory Management, September 1995.
/* * "Memory management is where the rubber meets the road -- if we do the wrong * thing at any level, the results will not be good. And if we don't make the * levels work well together, we are in serious trouble." (1) * * (1) Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles, *&&&&"Dynamic Storage Allocation: A Survey and Critical Review", *&&&&in Proc. 1995 Int'l. Workshop on Memory Management, September 1995. */
Python引入了内存池机制, 用于管理对小块内存的申请和释放
1. 如果要分配的内存空间大于 SMALL_REQUEST_THRESHOLD bytes(512 bytes), 将直接使用layer 1的内存分配接口进行分配
2. 否则, 使用不同的block来满足分配需求
1. 如果要分配的内存空间大于 SMALL_REQUEST_THRESHOLD bytes(512 bytes), 将直接使用layer 1的内存分配接口进行分配2. 否则, 使用不同的block来满足分配需求
整个小块内存池可以视为一个层次结构
1. 内存池(概念上的, 标识Python对于整个小块内存分配和释放的内存管理机制)
1. 内存池(概念上的, 标识Python对于整个小块内存分配和释放的内存管理机制)2. arena3. pool4. block
Python内存的最小单位, 所有block长度都是8字节对齐的
注意这里block只是一个概念, 在源代码中并没有实体存在.
不同类型block, 对应不同内存大小, 这个内存大小的值被称为size class.
不同长度的block
* Request in bytes
Size of allocated block
Size class idx
* ----------------------------------------------------------------
0, SMALL_REQUEST_THRESHOLD + 1 and up: routed to the underlying
allocator.
123456789101112131415161718
* Request in bytes&&&& Size of allocated block&&&&&&Size class idx * ---------------------------------------------------------------- *&&&&&&&&1-8&&&&&&&&&&&&&&&&&&&& 8&&&&&&&&&&&&&&&&&&&&&& 0 *&&&&&&&&9-16&&&&&&&&&&&&&&&&&& 16&&&&&&&&&&&&&&&&&&&&&& 1 *&&&&&& 17-24&&&&&&&&&&&&&&&&&& 24&&&&&&&&&&&&&&&&&&&&&& 2 *&&&&&& 25-32&&&&&&&&&&&&&&&&&& 32&&&&&&&&&&&&&&&&&&&&&& 3 *&&&&&& 33-40&&&&&&&&&&&&&&&&&& 40&&&&&&&&&&&&&&&&&&&&&& 4 *&&&&&& 41-48&&&&&&&&&&&&&&&&&& 48&&&&&&&&&&&&&&&&&&&&&& 5 *&&&&&& 49-56&&&&&&&&&&&&&&&&&& 56&&&&&&&&&&&&&&&&&&&&&& 6 *&&&&&& 57-64&&&&&&&&&&&&&&&&&& 64&&&&&&&&&&&&&&&&&&&&&& 7 *&&&&&& 65-72&&&&&&&&&&&&&&&&&& 72&&&&&&&&&&&&&&&&&&&&&& 8 *&&&&&&&&...&&&&&&&&&&&&&&&&&& ...&&&&&&&&&&&&&&&&&&&& ... *&&&&&&497-504&&&&&&&&&&&&&&&& 504&&&&&&&&&&&&&&&&&&&&&&62 *&&&&&&505-512&&&&&&&&&&&&&&&& 512&&&&&&&&&&&&&&&&&&&&&&63 * *&&&&&&0, SMALL_REQUEST_THRESHOLD + 1 and up: routed to the underlying *&&&&&&allocator. */
申请一块大小28字节的内存, 实际从内存中划到32字节的一个block (从size class index为3的pool里面划出)
申请一块大小28字节的内存, 实际从内存中划到32字节的一个block (从size class index为3的pool里面划出)
注意: 这里有个Size class idx, 这个主要为了后面pool中用到
size class和size class index之间的转换
#define ALIGNMENT
/* must be 2^N */
#define ALIGNMENT_SHIFT
#define ALIGNMENT_MASK
(ALIGNMENT - 1)
// size class index =& size class
#define INDEX2SIZE(I) (((uint)(I) + 1)
size class index
size = (uint)(nbytes - 1) && ALIGNMENT_SHIFT;
(8 - 1) / 8 = 0
(16 - 8) / 8 = 1
123456789101112
#define ALIGNMENT&&&&&&&&&&&&&& 8&&&&&&&&&&&&&& /* must be 2^N */#define ALIGNMENT_SHIFT&&&&&&&& 3#define ALIGNMENT_MASK&&&&&&&&&&(ALIGNMENT - 1)&// size class index =& size class#define INDEX2SIZE(I) (((uint)(I) + 1)&&size class indexsize = (uint)(nbytes - 1) && ALIGNMENT_SHIFT;&/* 即&&&&(8 - 1) / 8 = 0&&&&(16 - 8) / 8 = 1*/
pool管理block, 一个pool管理着一堆有固定大小的内存块
本质: pool管理着一大块内存, 它有一定的策略, 将这块大的内存划分为多个大小一致的小块内存.
在Python中, 一个pool的大小通常为一个系统内存页. 4kB
obmalloc.c
#define SYSTEM_PAGE_SIZE
(4 * 1024)
#define SYSTEM_PAGE_SIZE_MASK
(SYSTEM_PAGE_SIZE - 1)
#define POOL_SIZE
SYSTEM_PAGE_SIZE
/* must be 2^N */
#define POOL_SIZE_MASK
SYSTEM_PAGE_SIZE_MASK
obmalloc.c&#define SYSTEM_PAGE_SIZE&&&&&&&&(4 * 1024)#define SYSTEM_PAGE_SIZE_MASK&& (SYSTEM_PAGE_SIZE - 1)&#define POOL_SIZE&&&&&&&&&&&&&& SYSTEM_PAGE_SIZE&&&&&&&&/* must be 2^N */#define POOL_SIZE_MASK&&&&&&&&&&SYSTEM_PAGE_SIZE_MASK
pool的4kB内存 = pool_header + block集合(N多大小一样的block)
pool_header
/* Pool for small blocks. */
struct pool_header {
union { block *_
/* number of allocated blocks
/* pool's free list head
struct pool_header *
/* next pool of this size class
struct pool_header *
/* previous pool
/* index into arenas of base adr */
/* block size class index
*/ - size class index
/* bytes to virgin block
/* largest valid nextoffset
123456789101112
/* Pool for small blocks. */struct pool_header {&&&&union { block *_padding;&&&&&&&&&&&&uint count; } ref;&&&&&&&&&&/* number of allocated blocks&&&&*/&&&&block *freeblock;&&&&&&&&&&&&&&&&&& /* pool's free list head&&&&&&&& */&&&&struct pool_header *nextpool;&&&&&& /* next pool of this size class&&*/&&&&struct pool_header *prevpool;&&&&&& /* previous pool&&&&&& ""&&&&&&&&*/&&&&uint arenaindex;&&&&&&&&&&&&&&&&&&&&/* index into arenas of base adr */&&&&uint szidx;&&&&&&&&&&&&&&&&&&&&&&&& /* block size class index&&&&&&&&*/ - size class index&&&&uint nextoffset;&&&&&&&&&&&&&&&&&&&&/* bytes to virgin block&&&&&&&& */&&&&uint maxnextoffset;&&&&&&&&&&&&&&&& /* largest valid nextoffset&&&&&&*/};
pool_header的作用
1. 与其他pool链接, 组成双向链表
2. 维护pool中可用的block, 单链表
3. 保存 szidx , 这个和该pool中block的大小有关系, (block size=8, szidx=0), (block size=16, szidx=1)...用于内存分配时匹配到拥有对应大小block的pool
4. arenaindex, 后面说
1. 与其他pool链接, 组成双向链表2. 维护pool中可用的block, 单链表3. 保存 szidx , 这个和该pool中block的大小有关系, (block size=8, szidx=0), (block size=16, szidx=1)...用于内存分配时匹配到拥有对应大小block的pool4. arenaindex, 后面说
pool初始化
从内存中初始化一个全新的空的pool
Objects/obmalloc.c的
PyObject_Malloc(size_t nbytes)
init_pool:
// 1. 连接到 used_pools 双向链表, 作为表头
// 注意, 这里 usedpools[0] 保存着 block size = 8 的所有used_pools的表头
/* Frontlink to used pools. */
next = usedpools[size + size]; /* == prev */
pool-&nextpool =
pool-&prevpool =
next-&nextpool =
next-&prevpool =
pool-&ref.count = 1;
// 如果已经初始化过了...这里看初始化, 跳过
if (pool-&szidx == size) {
/* Luckily, this pool last contained blocks
* of the same size class, so its header
* and free list are already initialized.
bp = pool-&
pool-&freeblock = *(block **)
return (void *)
* Initialize the pool header, set up the free list to
* contain just the second block, and return the first
// 开始初始化pool_header
// 这里 size = (uint)(nbytes - 1) && ALIGNMENT_SHIFT;
其实是Size class idx, 即szidx
pool-&szidx =
// 计算获得每个block的size
size = INDEX2SIZE(size);
// 注意 #define POOL_OVERHEAD
ROUNDUP(sizeof(struct pool_header))
// bp =& 初始化为pool + pool_header size,
跳过pool_header的内存
bp = (block *)pool + POOL_OVERHEAD;
// 计算偏移量, 这里的偏移量是绝对值
// #define POOL_SIZE
SYSTEM_PAGE_SIZE
/* must be 2^N */
// POOL_SIZE = 4kb, POOL_OVERHEAD = pool_header size
// 下一个偏移位置: pool_header size + 2 * size
pool-&nextoffset = POOL_OVERHEAD + (size maxnextoffset = POOL_SIZE -
// freeblock指向 bp + size = pool_header size + size
pool-&freeblock = bp +
// 赋值NULL
*(block **)(pool-&freeblock) = NULL;
return (void *)
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
void *PyObject_Malloc(size_t nbytes){&&...&&&&&&&&&&&init_pool:&&&&&&&&&&&&// 1. 连接到 used_pools 双向链表, 作为表头&&&&&&&&&&&&// 注意, 这里 usedpools[0] 保存着 block size = 8 的所有used_pools的表头&&&&&&&&&&&&/* Frontlink to used pools. */&&&&&&&&&&&&next = usedpools[size + size]; /* == prev */&&&&&&&&&&&&pool-&nextpool = next;&&&&&&&&&&&&pool-&prevpool = next;&&&&&&&&&&&&next-&nextpool = pool;&&&&&&&&&&&&next-&prevpool = pool;&&&&&&&&&&&&pool-&ref.count = 1;&&&&&&&&&&&&&// 如果已经初始化过了...这里看初始化, 跳过&&&&&&&&&&&&if (pool-&szidx == size) {&&&&&&&&&&&&&&&&/* Luckily, this pool last contained blocks&&&&&&&&&&&&&&&& * of the same size class, so its header&&&&&&&&&&&&&&&& * and free list are already initialized.&&&&&&&&&&&&&&&& */&&&&&&&&&&&&&&&&bp = pool-&freeblock;&&&&&&&&&&&&&&&&pool-&freeblock = *(block **)bp;&&&&&&&&&&&&&&&&UNLOCK();&&&&&&&&&&&&&&&&return (void *)bp;&&&&&&&&&&&&}&&&&&&&&&&&&&/*&&&&&&&&&&&& * Initialize the pool header, set up the free list to&&&&&&&&&&&& * contain just the second block, and return the first&&&&&&&&&&&& * block.&&&&&&&&&&&& */&&&&&&&&&&&&// 开始初始化pool_header&&&&&&&&&&&&// 这里 size = (uint)(nbytes - 1) && ALIGNMENT_SHIFT;&&其实是Size class idx, 即szidx&&&&&&&&&&&&pool-&szidx = size;&&&&&&&&&&&&&// 计算获得每个block的size&&&&&&&&&&&&size = INDEX2SIZE(size);&&&&&&&&&&&&&// 注意 #define POOL_OVERHEAD&&&&&&&&&& ROUNDUP(sizeof(struct pool_header))&&&&&&&&&&&&// bp =& 初始化为pool + pool_header size,&&跳过pool_header的内存&&&&&&&&&&&&bp = (block *)pool + POOL_OVERHEAD;&&&&&&&&&&&&&// 计算偏移量, 这里的偏移量是绝对值&&&&&&&&&&&&// #define POOL_SIZE&&&&&&&&&&&&&& SYSTEM_PAGE_SIZE&&&&&&&&/* must be 2^N */&&&&&&&&&&&&// POOL_SIZE = 4kb, POOL_OVERHEAD = pool_header size&&&&&&&&&&&&// 下一个偏移位置: pool_header size + 2 * size&&&&&&&&&&&&pool-&nextoffset = POOL_OVERHEAD + (size maxnextoffset = POOL_SIZE - size;&&&&&&&&&&&&&// freeblock指向 bp + size = pool_header size + size&&&&&&&&&&&&pool-&freeblock = bp + size;&&&&&&&&&&&&&// 赋值NULL&&&&&&&&&&&&*(block **)(pool-&freeblock) = NULL;&&&&&&&&&&&&UNLOCK();&&&&&&&&&&&&return (void *)bp;&&&&&&&&}
初始化后的图
pool进行block分配 – 0 总体代码
总体分配的代码如下
if (pool != pool-&nextpool) {
* There is a used pool for this size class.
* Pick up the head block of its free list.
++pool-&ref.
bp = pool-& // 指针指向空闲block起始位置
assert(bp != NULL);
// 调整 pool-&freeblock (假设A节点)指向链表下一个, 即bp首字节指向的下一个节点(假设B节点) , 如果此时!= NULL
// 表示 A节点可用, 直接返回
if ((pool-&freeblock = *(block **)bp) != NULL) {
return (void *)
* Reached the end of the free list, try to extend it.
// 有足够的空间, 分配一个, pool-&freeblock 指向后移
if (pool-&nextoffset maxnextoffset) {
/* There is room for another block. */
// 变更位置信息
pool-&freeblock = (block*)pool +
pool-&nextoffset += INDEX2SIZE(size);
*(block **)(pool-&freeblock) = NULL; // 注意, 指向NULL
return (void *)
/* Pool is full, unlink from used pools. */
// 满了, 需要从下一个pool获取
next = pool-&
pool = pool-&
next-&prevpool =
pool-&nextpool =
return (void *)
123456789101112131415161718192021222324252627282930313233343536373839404142434445
&&&& if (pool != pool-&nextpool) {&& //&&&&&&&&&&&&/*&&&&&&&&&&&& * There is a used pool for this size class.&&&&&&&&&&&& * Pick up the head block of its free list.&&&&&&&&&&&& */&&&&&&&&&&&&++pool-&ref.count;&&&&&&&&&&&&bp = pool-&freeblock; // 指针指向空闲block起始位置&&&&&&&&&&&&assert(bp != NULL);&&&&&&&&&&&&&// 代码-1&&&&&&&&&&&&// 调整 pool-&freeblock (假设A节点)指向链表下一个, 即bp首字节指向的下一个节点(假设B节点) , 如果此时!= NULL&&&&&&&&&&&&// 表示 A节点可用, 直接返回&&&&&&&&&&&&if ((pool-&freeblock = *(block **)bp) != NULL) {&&&&&&&&&&&&&&&&UNLOCK();&&&&&&&&&&&&&&&&return (void *)bp;&&&&&&&&&&&&}&&&&&&&&&&&&&// 代码-2&&&&&&&&&&&&/*&&&&&&&&&&&& * Reached the end of the free list, try to extend it.&&&&&&&&&&&& */&&&&&&&&&&&&// 有足够的空间, 分配一个, pool-&freeblock 指向后移&&&&&&&&&&&&if (pool-&nextoffset maxnextoffset) {&&&&&&&&&&&&&&&&/* There is room for another block. */&&&&&&&&&&&&&&&&// 变更位置信息&&&&&&&&&&&&&&&&pool-&freeblock = (block*)pool +&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&pool-&nextoffset;&&&&&&&&&&&&&&&&pool-&nextoffset += INDEX2SIZE(size);&&&&&&&&&&&&&&&&&*(block **)(pool-&freeblock) = NULL; // 注意, 指向NULL&&&&&&&&&&&&&&&&UNLOCK();&&&&&&&&&&&&&&&&&// 返回bp&&&&&&&&&&&&&&&&return (void *)bp;&&&&&&&&&&&&}&&&&&&&&&&&&&// 代码-3&&&&&&&&&&&&/* Pool is full, unlink from used pools. */&&// 满了, 需要从下一个pool获取&&&&&&&&&&&&next = pool-&nextpool;&&&&&&&&&&&&pool = pool-&prevpool;&&&&&&&&&&&&next-&prevpool = pool;&&&&&&&&&&&&pool-&nextpool = next;&&&&&&&&&&&&UNLOCK();&&&&&&&&&&&&return (void *)bp;&&&&&&&&}
pool进行block分配 – 1 刚开始
内存块尚未分配完, 且此时不存在回收的block, 全新进来的时候, 分配第一块block
(pool-&freeblock = *(block **)bp) == NULL
(pool-&freeblock = *(block **)bp) == NULL
所以进入的逻辑是代码-2
bp = pool-& // 指针指向空闲block起始位置
* Reached the end of the free list, try to extend it.
// 有足够的空间, 分配一个, pool-&freeblock 指向后移
if (pool-&nextoffset maxnextoffset) {
/* There is room for another block. */
// 变更位置信息
pool-&freeblock = (block*)pool +
pool-&nextoffset += INDEX2SIZE(size);
*(block **)(pool-&freeblock) = NULL; // 注意, 指向NULL
return (void *)
12345678910111213141516171819202122
&&&&&&&&&&&&bp = pool-&freeblock; // 指针指向空闲block起始位置&&&&&&&&&&&&&.....&&&&&&&&&&&&&// 代码-2&&&&&&&&&&&&/*&&&&&&&&&&&& * Reached the end of the free list, try to extend it.&&&&&&&&&&&& */&&&&&&&&&&&&// 有足够的空间, 分配一个, pool-&freeblock 指向后移&&&&&&&&&&&&if (pool-&nextoffset maxnextoffset) {&&&&&&&&&&&&&&&&/* There is room for another block. */&&&&&&&&&&&&&&&&// 变更位置信息&&&&&&&&&&&&&&&&pool-&freeblock = (block*)pool +&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&pool-&nextoffset;&&&&&&&&&&&&&&&&pool-&nextoffset += INDEX2SIZE(size);&&&&&&&&&&&&&&&&&*(block **)(pool-&freeblock) = NULL; // 注意, 指向NULL&&&&&&&&&&&&&&&&UNLOCK();&&&&&&&&&&&&&&&&&// 返回bp&&&&&&&&&&&&&&&&return (void *)bp;&&&&&&&&&&&&}
pool进行block分配 – 2 回收了某几个block
回收涉及的代码
PyObject_Free(void *p)
poolp next,
pool = POOL_ADDR(p);
if (Py_ADDRESS_IN_RANGE(p, pool)) {
/* We allocated this address. */
/* Link p to the start of the pool's freeblock list.
* the pool had at least the p block outstanding, the pool
* wasn't empty (so it's already in a usedpools[] list, or
* was full and is in no list -- it's not in the freeblocks
* list in any case).
assert(pool-&ref.count & 0);
/* else it was empty */
// p被释放, p的第一个字节值被设置为当前freeblock的值
*(block **)p = lastfree = pool-&
// freeblock被更新为指向p的首地址
pool-&freeblock = (block *)p;
// 相当于往list中头插入了一个节点
1234567891011121314151617181920212223242526272829
voidPyObject_Free(void *p){&&&&poolp pool;&&&&block *lastfree;&&&&poolp next, prev;&&&&uint size;&&&&&pool = POOL_ADDR(p);&&&&if (Py_ADDRESS_IN_RANGE(p, pool)) {&&&&&&&&/* We allocated this address. */&&&&&&&&LOCK();&&&&&&&&/* Link p to the start of the pool's freeblock list.&&Since&&&&&&&& * the pool had at least the p block outstanding, the pool&&&&&&&& * wasn't empty (so it's already in a usedpools[] list, or&&&&&&&& * was full and is in no list -- it's not in the freeblocks&&&&&&&& * list in any case).&&&&&&&& */&&&&&&&&assert(pool-&ref.count & 0);&&&&&&&&&&&&/* else it was empty */&&&&&&&&// p被释放, p的第一个字节值被设置为当前freeblock的值&&&&&&&&*(block **)p = lastfree = pool-&freeblock;&&&&&&&&// freeblock被更新为指向p的首地址&&&&&&&&pool-&freeblock = (block *)p;&&&&&&&&&// 相当于往list中头插入了一个节点&&&&& ...&&&&}}
没释放一个block, 该block就会变成 pool-&freeblock 的头节点, 而单链表一个节点如何指向下一个节点呢? 通过赋值, 节点内存空间保存着下个节点的地址, 最后一个节点指向NULL(知道上面代码-1的判断条件了吧&_
假设已经连续分配了5块, 第1块和第4块被释放
此时内存图示
此时再一个block分配调用进来, 执行分配, 进入的逻辑是代码-1
bp = pool-& // 指针指向空闲block起始位置
// 调整 pool-&freeblock (假设A节点)指向链表下一个, 即bp首字节指向的下一个节点(假设B节点) , 如果此时!= NULL
// 表示 A节点可用, 直接返回
if ((pool-&freeblock = *(block **)bp) != NULL) {
return (void *)
&&&&&&&&&&&&bp = pool-&freeblock; // 指针指向空闲block起始位置&&&&&&&&&&&&// 代码-1&&&&&&&&&&&&// 调整 pool-&freeblock (假设A节点)指向链表下一个, 即bp首字节指向的下一个节点(假设B节点) , 如果此时!= NULL&&&&&&&&&&&&// 表示 A节点可用, 直接返回&&&&&&&&&&&&if ((pool-&freeblock = *(block **)bp) != NULL) {&&&&&&&&&&&&&&&&UNLOCK();&&&&&&&&&&&&&&&&return (void *)bp;&&&&&&&&&&&&}
pool进行block分配 – 3 pool用完了
pool中内存空间都用完了, 进入代码-3
bp = pool-& // 指针指向空闲block起始位置
/* Pool is full, unlink from used pools. */
// 满了, 需要从下一个pool获取
next = pool-&
pool = pool-&
next-&prevpool =
pool-&nextpool =
return (void *)
12345678910
&&&&&&&&&&&&bp = pool-&freeblock; // 指针指向空闲block起始位置&&&&&&&&&&&&&// 代码-3&&&&&&&&&&&&/* Pool is full, unlink from used pools. */&&// 满了, 需要从下一个pool获取&&&&&&&&&&&&next = pool-&nextpool;&&&&&&&&&&&&pool = pool-&prevpool;&&&&&&&&&&&&next-&prevpool = pool;&&&&&&&&&&&&pool-&nextpool = next;&&&&&&&&&&&&UNLOCK();&&&&&&&&&&&&return (void *)bp;
获取下一个pool(链表上每个pool的block size都是一致的)
好了, pool到此位置, 下篇进入arena
打赏支持我写出更多好文章,谢谢!
打赏支持我写出更多好文章,谢谢!
任选一种支付方式
关于作者:
可能感兴趣的话题
o 240 回复
关于 Python 频道
Python频道分享 Python 开发技术、相关的行业动态。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2017 伯乐在线

我要回帖

更多关于 java 内存管理机制 的文章

 

随机推荐