Python 的内存管理架构(Objects/obmalloc.c):
_____ ______ ______ ________
[ int ] [ dict ] [ list ] ... [ string ] Python core |
+3 | | |
_______________________________ | |
[ Python's object allocator ] | |
+2 | ####### Object memory ####### | |
______________________________________________________________ |
[ Python's raw memory allocator (PyMem_ API) ] |
+1 | | |
__________________________________________________________________
[ Underlying general-purpose allocator (ex: C library malloc) ]
0 | |
0. C语言库函数提供的接口
1. PyMem_*家族,是对 C中的 malloc、realloc和free 简单的封装,提供底层的控制接口。
2. PyObject_* 家族,高级的内存控制接口。
3. 对象类型相关的管理接口
PyMem_*
PyMem_家族:低级的内存分配接口(low-level memory allocation interfaces)
Python 对C中的 malloc、realloc和free 提供了简单的封装:
为什么要这么多次一举:
- 不同的C实现对于malloc(0)产生的结果有会所不同,而PyMem_MALLOC(0)会转成malloc(1).
- 不用的C实现的malloc与free混用会有潜在的问题。python提供封装可以避免这个问题。
- Python提供了宏和函数,但是宏无法避免这个问题,故编写扩展是应避免使用宏
源码:
Include/pymem.h #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 Objects/object.c /* Python's malloc wrappers (see pymem.h) */ void * PyMem_Malloc(size_t nbytes) { return PyMem_MALLOC(nbytes); } ...
PyMem_New 和 PyMem_NEW
PyMem_Resize和 PyMem_RESIZE
它们可以感知类型的大小
#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_Del PyMem_Free #define PyMem_DEL PyMem_FREE
PyObject_*
PyObject_*家族,是高级的内存控制接口(high-level object memory interfaces)。
注意
- 不要和PyMem_*家族混用!!
- 除非有特殊的内粗管理要求,否则应该坚持使用PyObject_*
源码
Include/objimpl.h #define PyObject_New(type, typeobj) \ ( (type *) _PyObject_New(typeobj) ) #define PyObject_NewVar(type, typeobj, n) \ ( (type *) _PyObject_NewVar((typeobj), (n)) ) Objects/object.c PyObject * _PyObject_New(PyTypeObject *tp) { PyObject *op; op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); if (op == NULL) return PyErr_NoMemory(); return PyObject_INIT(op, tp); } PyVarObject * _PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems) { PyVarObject *op; const size_t size = _PyObject_VAR_SIZE(tp, nitems); op = (PyVarObject *) PyObject_MALLOC(size); if (op == NULL) return (PyVarObject *)PyErr_NoMemory(); return PyObject_INIT_VAR(op, tp, nitems); }
它们执行两项操作:
- 分配内存:PyObject_MALLOC
- 部分初始化对象:PyObject_INIT和PyObject_INIT_VAR
初始化没什么好看到,但是这个MALLOC就有点复杂无比了...
PyObject_{Malloc、Free}
这个和PyMem_*中的3个可是大不一样了,复杂的厉害!
void * PyObject_Malloc(size_t nbytes) void * PyObject_Realloc(void *p, size_t nbytes) void PyObject_Free(void *p)
Python程序运行时频繁地需要创建和销毁小对象,为了避免大量的malloc和free操作,Python使用了内存池的技术。
- 一系列的 arena(每个管理256KB) 构成一个内存区域的链表
- 每个 arena 有很多个 pool(每个4KB) 构成
- 每次内存的申请释放将在一个 pool 内进行
单次申请内存块
当申请大小在 1~256 字节之间的内存时,使用内存池(申请0或257字节以上时,将退而使用我们前面提到的PyMem_Malloc)。
每次申请时,实际分配的空间将按照某个字节数对齐,下表中为8字节(比如PyObject_Malloc(20)字节将分配24字节)。
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
... ... ...
241-248 248 30
249-256 256 31
0, 257 and up: routed to the underlying allocator.
这些参数由一些宏进行控制:
#define ALIGNMENT 8 /* must be 2^N */ /* Return the number of bytes in size class I, as a uint. */ #define INDEX2SIZE(I) (((uint)(I) + 1) << ALIGNMENT_SHIFT) #define SMALL_REQUEST_THRESHOLD 256
pool
每次申请的内存块都是需要在 pool 中进行分配,一个pool的大小是 4k。由下列宏进行控制:
#define SYSTEM_PAGE_SIZE (4 * 1024)
#define POOL_SIZE SYSTEM_PAGE_SIZE /* must be 2^N */
每个pool的头部的定义如下:
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 */ uint nextoffset; /* bytes to virgin block */ uint maxnextoffset; /* largest valid nextoffset */ };
注意,其中有个成员 szidx,对应前面列表中最后一列的 Size class idx。这也说明一个问题:每个 pool 只能分配固定大小的内存块(比如,只分配16字节的块,或者只分配24字节的块...)。
要能分配前面列表中各种大小的内存块,必须有多个 pool。同一大小的pool分配完毕,也需要新的pool。多个pool依次构成一个链表
arena
多个pool对象使用被称为 arena 的东西进行管理。
struct arena_object { uptr address; block* pool_address; uint nfreepools; uint ntotalpools; struct pool_header* freepools; struct arena_object* nextarena; struct arena_object* prevarena; };
arean控制的内存的大小由下列宏控制:
#define ARENA_SIZE (256 << 10) /* 256KB */
一系列的 arena 构成一个链表。
引用计数与垃圾收集
Python中多数对象的生命周期是通过引用计数来控制的,从而实现了内存的动态管理。
但是引用计数有一个致命的问题:循环引用!
为了打破循环引用,Python引入了垃圾收集技术。

Python和C 各有優勢,選擇應基於項目需求。 1)Python適合快速開發和數據處理,因其簡潔語法和動態類型。 2)C 適用於高性能和系統編程,因其靜態類型和手動內存管理。

選擇Python還是C 取決於項目需求:1)如果需要快速開發、數據處理和原型設計,選擇Python;2)如果需要高性能、低延遲和接近硬件的控制,選擇C 。

通過每天投入2小時的Python學習,可以有效提升編程技能。 1.學習新知識:閱讀文檔或觀看教程。 2.實踐:編寫代碼和完成練習。 3.複習:鞏固所學內容。 4.項目實踐:應用所學於實際項目中。這樣的結構化學習計劃能幫助你係統掌握Python並實現職業目標。

在兩小時內高效學習Python的方法包括:1.回顧基礎知識,確保熟悉Python的安裝和基本語法;2.理解Python的核心概念,如變量、列表、函數等;3.通過使用示例掌握基本和高級用法;4.學習常見錯誤與調試技巧;5.應用性能優化與最佳實踐,如使用列表推導式和遵循PEP8風格指南。

Python適合初學者和數據科學,C 適用於系統編程和遊戲開發。 1.Python簡潔易用,適用於數據科學和Web開發。 2.C 提供高性能和控制力,適用於遊戲開發和系統編程。選擇應基於項目需求和個人興趣。

Python更適合數據科學和快速開發,C 更適合高性能和系統編程。 1.Python語法簡潔,易於學習,適用於數據處理和科學計算。 2.C 語法複雜,但性能優越,常用於遊戲開發和系統編程。

每天投入兩小時學習Python是可行的。 1.學習新知識:用一小時學習新概念,如列表和字典。 2.實踐和練習:用一小時進行編程練習,如編寫小程序。通過合理規劃和堅持不懈,你可以在短時間內掌握Python的核心概念。

Python更易學且易用,C 則更強大但複雜。 1.Python語法簡潔,適合初學者,動態類型和自動內存管理使其易用,但可能導致運行時錯誤。 2.C 提供低級控制和高級特性,適合高性能應用,但學習門檻高,需手動管理內存和類型安全。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

WebStorm Mac版
好用的JavaScript開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

SublimeText3 Linux新版
SublimeText3 Linux最新版