cari
Rumahpembangunan bahagian belakangTutorial Python从Python的源码浅要剖析Python的内存管理

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 提供了简单的封装:

201541692301579.jpg (301×158)

为什么要这么多次一举:

  •     不同的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);
}
...


除了对C的简单封装外,Python还提供了4个宏

    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);
}

它们执行两项操作:

  1.     分配内存:PyObject_MALLOC
  2.     部分初始化对象: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引入了垃圾收集技术。

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Menyenaraikan senarai di Python: Memilih kaedah yang betulMenyenaraikan senarai di Python: Memilih kaedah yang betulMay 14, 2025 am 12:11 AM

Tomergelistsinpython, operator youCanusethe, extendmethod, listcomprehension, oritertools.chain, eachwithspecificadvantages: 1) operatorSimpleButlessefficientficorlargelists;

Bagaimana untuk menggabungkan dua senarai dalam Python 3?Bagaimana untuk menggabungkan dua senarai dalam Python 3?May 14, 2025 am 12:09 AM

Dalam Python 3, dua senarai boleh disambungkan melalui pelbagai kaedah: 1) Pengendali penggunaan, yang sesuai untuk senarai kecil, tetapi tidak cekap untuk senarai besar; 2) Gunakan kaedah Extend, yang sesuai untuk senarai besar, dengan kecekapan memori yang tinggi, tetapi akan mengubah suai senarai asal; 3) menggunakan * pengendali, yang sesuai untuk menggabungkan pelbagai senarai, tanpa mengubah suai senarai asal; 4) Gunakan itertools.chain, yang sesuai untuk set data yang besar, dengan kecekapan memori yang tinggi.

Rentetan senarai concatenate pythonRentetan senarai concatenate pythonMay 14, 2025 am 12:08 AM

Menggunakan kaedah Join () adalah cara yang paling berkesan untuk menyambungkan rentetan dari senarai di Python. 1) Gunakan kaedah Join () untuk menjadi cekap dan mudah dibaca. 2) Kitaran menggunakan pengendali tidak cekap untuk senarai besar. 3) Gabungan pemahaman senarai dan menyertai () sesuai untuk senario yang memerlukan penukaran. 4) Kaedah mengurangkan () sesuai untuk jenis pengurangan lain, tetapi tidak cekap untuk penyambungan rentetan. Kalimat lengkap berakhir.

Pelaksanaan Python, apa itu?Pelaksanaan Python, apa itu?May 14, 2025 am 12:06 AM

PythonexecutionistheprocessoftransformingpythoncodeIntoExecutableInstructions.1) TheinterpreterreadsTheCode, convertingIntoByteCode, yang mana -mana

Python: Apakah ciri -ciri utamaPython: Apakah ciri -ciri utamaMay 14, 2025 am 12:02 AM

Ciri -ciri utama Python termasuk: 1. Sintaks adalah ringkas dan mudah difahami, sesuai untuk pemula; 2. Sistem jenis dinamik, meningkatkan kelajuan pembangunan; 3. Perpustakaan standard yang kaya, menyokong pelbagai tugas; 4. Komuniti dan ekosistem yang kuat, memberikan sokongan yang luas; 5. Tafsiran, sesuai untuk skrip dan prototaip cepat; 6. Sokongan multi-paradigma, sesuai untuk pelbagai gaya pengaturcaraan.

Python: pengkompil atau penterjemah?Python: pengkompil atau penterjemah?May 13, 2025 am 12:10 AM

Python adalah bahasa yang ditafsirkan, tetapi ia juga termasuk proses penyusunan. 1) Kod python pertama kali disusun ke dalam bytecode. 2) Bytecode ditafsirkan dan dilaksanakan oleh mesin maya Python. 3) Mekanisme hibrid ini menjadikan python fleksibel dan cekap, tetapi tidak secepat bahasa yang disusun sepenuhnya.

Python untuk gelung vs semasa gelung: Bila menggunakan yang mana?Python untuk gelung vs semasa gelung: Bila menggunakan yang mana?May 13, 2025 am 12:07 AM

UseAforLoopWheniteratingOvereForforpecificNumbimes; Useaphileloopwhencontinuinguntilaconditionismet.forloopsareidealforknownownsequences, sementara yang tidak digunakan.

Gelung Python: Kesalahan yang paling biasaGelung Python: Kesalahan yang paling biasaMay 13, 2025 am 12:07 AM

Pythonloopscanleadtoerrorslikeinfiniteloops, pengubahsuaianListsduringiteration, off-by-oneerrors, sifar-indexingissues, andnestedloopinefficies.toavoidthese: 1) use'i

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Nordhold: Sistem Fusion, dijelaskan
4 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
Mandragora: Whispers of the Witch Tree - Cara Membuka Kunci Cangkuk Bergelut
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌

Alat panas

VSCode Windows 64-bit Muat Turun

VSCode Windows 64-bit Muat Turun

Editor IDE percuma dan berkuasa yang dilancarkan oleh Microsoft

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SecLists

SecLists

SecLists ialah rakan penguji keselamatan muktamad. Ia ialah koleksi pelbagai jenis senarai yang kerap digunakan semasa penilaian keselamatan, semuanya di satu tempat. SecLists membantu menjadikan ujian keselamatan lebih cekap dan produktif dengan menyediakan semua senarai yang mungkin diperlukan oleh penguji keselamatan dengan mudah. Jenis senarai termasuk nama pengguna, kata laluan, URL, muatan kabur, corak data sensitif, cangkerang web dan banyak lagi. Penguji hanya boleh menarik repositori ini ke mesin ujian baharu dan dia akan mempunyai akses kepada setiap jenis senarai yang dia perlukan.

PhpStorm versi Mac

PhpStorm versi Mac

Alat pembangunan bersepadu PHP profesional terkini (2018.2.1).

EditPlus versi Cina retak

EditPlus versi Cina retak

Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod