Files
hustoj/web/python-docs/c-api/memory.html
2025-03-09 17:10:56 +08:00

766 lines
72 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_CN">
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>内存管理 &#8212; Python 3.8.20 文档</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<script src="../_static/translations.js"></script>
<script src="../_static/sidebar.js"></script>
<link rel="search" type="application/opensearchdescription+xml"
title="在 Python 3.8.20 文档 中搜索"
href="../_static/opensearch.xml"/>
<link rel="author" title="关于这些文档" href="../about.html" />
<link rel="index" title="索引" href="../genindex.html" />
<link rel="search" title="搜索" href="../search.html" />
<link rel="copyright" title="版权所有" href="../copyright.html" />
<link rel="next" title="对象实现支持" href="objimpl.html" />
<link rel="prev" title="Python初始化配置" href="init_config.html" />
<link rel="canonical" href="https://docs.python.org/3/c-api/memory.html" />
<style>
@media only screen {
table.full-width-table {
width: 100%;
}
}
</style>
<link rel="shortcut icon" type="image/png" href="../_static/py.svg" />
<script type="text/javascript" src="../_static/copybutton.js"></script>
<script type="text/javascript" src="../_static/menu.js"></script>
</head>
<body>
<div class="mobile-nav">
<input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation"
aria-pressed="false" aria-expanded="false" role="button" aria-label="Menu" />
<label for="menuToggler" class="toggler__label">
<span></span>
</label>
<nav class="nav-content" role="navigation">
<a href="https://www.python.org/" class="nav-logo">
<img src="../_static/py.svg" alt="Logo"/>
</a>
<div class="version_switcher_placeholder"></div>
<form role="search" class="search" action="../search.html" method="get">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon">
<path fill-rule="nonzero"
d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" fill="#444"></path>
</svg>
<input type="text" name="q" aria-label="快速搜索"/>
<input type="submit" value="转向"/>
</form>
</nav>
<div class="menu-wrapper">
<nav class="menu" role="navigation" aria-label="main navigation">
<div class="language_switcher_placeholder"></div>
<h3><a href="../contents.html">目录</a></h3>
<ul>
<li><a class="reference internal" href="#">内存管理</a><ul>
<li><a class="reference internal" href="#overview">概述</a></li>
<li><a class="reference internal" href="#raw-memory-interface">原始内存接口</a></li>
<li><a class="reference internal" href="#memory-interface">内存接口</a></li>
<li><a class="reference internal" href="#object-allocators">对象分配器</a></li>
<li><a class="reference internal" href="#default-memory-allocators">默认内存分配器</a></li>
<li><a class="reference internal" href="#customize-memory-allocators">自定义内存分配器</a></li>
<li><a class="reference internal" href="#the-pymalloc-allocator">pymalloc 分配器</a><ul>
<li><a class="reference internal" href="#customize-pymalloc-arena-allocator">自定义 pymalloc Arena 分配器</a></li>
</ul>
</li>
<li><a class="reference internal" href="#tracemalloc-c-api">tracemalloc C API</a></li>
<li><a class="reference internal" href="#examples">例子</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="init_config.html"
title="上一章">Python初始化配置</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="objimpl.html"
title="下一章">对象实现支持</a></p>
<div role="note" aria-label="source link">
<h3>本页</h3>
<ul class="this-page-menu">
<li><a href="../bugs.html">报告 Bug</a></li>
<li>
<a href="https://github.com/python/cpython/blob/3.8/Doc/c-api/memory.rst"
rel="nofollow">显示源代码
</a>
</li>
</ul>
</div>
</nav>
</div>
</div>
<div id="outdated-warning" style="padding: .5em; text-align: center; background-color: #FFBABA; color: #6A0E0E;">
这个文档所针对的是一个已不再受支持的 Python 旧版本。
你应当升级版本,并阅读
<a href="/3/c-api/memory.html"> Python 当前稳定版本的文档</a>.
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>导航</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="总目录"
accesskey="I">索引</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python 模块索引"
>模块</a> |</li>
<li class="right" >
<a href="objimpl.html" title="对象实现支持"
accesskey="N">下一页</a> |</li>
<li class="right" >
<a href="init_config.html" title="Python初始化配置"
accesskey="P">上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python/C API 参考手册</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="memory-management">
<span id="memory"></span><h1>内存管理<a class="headerlink" href="#memory-management" title="永久链接至标题"></a></h1>
<section id="overview">
<span id="memoryoverview"></span><h2>概述<a class="headerlink" href="#overview" title="永久链接至标题"></a></h2>
<p>在 Python 中,内存管理涉及到一个包含所有 Python 对象和数据结构的私有堆heap。这个私有堆的管理由内部的 <em>Python 内存管理器Python memory manager</em> 保证。Python 内存管理器有不同的组件来处理各种动态存储管理方面的问题,如共享、分割、预分配或缓存。</p>
<p>在最底层,一个原始内存分配器通过与操作系统的内存管理器交互,确保私有堆中有足够的空间来存储所有与 Python 相关的数据。在原始内存分配器的基础上几个对象特定的分配器在同一堆上运行并根据每种对象类型的特点实现不同的内存管理策略。例如整数对象在堆内的管理方式不同于字符串、元组或字典因为整数需要不同的存储需求和速度与空间的权衡。因此Python 内存管理器将一些工作分配给对象特定分配器,但确保后者在私有堆的范围内运行。</p>
<p>Python 堆内存的管理是由解释器来执行用户对它没有控制权即使他们经常操作指向堆内内存块的对象指针理解这一点十分重要。Python 对象和其他内部缓冲区的堆空间分配是由 Python 内存管理器按需通过本文档中列出的 Python/C API 函数进行的。</p>
<p id="index-0">为了避免内存破坏,扩展的作者永远不应该试图用 C 库函数导出的函数来对 Python 对象进行操作,这些函数包括: <code class="xref c c-func docutils literal notranslate"><span class="pre">malloc()</span></code>, <code class="xref c c-func docutils literal notranslate"><span class="pre">calloc()</span></code>, <code class="xref c c-func docutils literal notranslate"><span class="pre">realloc()</span></code><code class="xref c c-func docutils literal notranslate"><span class="pre">free()</span></code>。这将导致 C 分配器和 Python 内存管理器之间的混用,引发严重后果,这是由于它们实现了不同的算法,并在不同的堆上操作。但是,我们可以安全地使用 C 库分配器为单独的目的分配和释放内存块,如下例所示:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">res</span><span class="p">;</span>
<span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">buf</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">malloc</span><span class="p">(</span><span class="n">BUFSIZ</span><span class="p">);</span><span class="w"> </span><span class="cm">/* for I/O */</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">PyErr_NoMemory</span><span class="p">();</span>
<span class="p">...</span><span class="n">Do</span><span class="w"> </span><span class="n">some</span><span class="w"> </span><span class="n">I</span><span class="o">/</span><span class="n">O</span><span class="w"> </span><span class="n">operation</span><span class="w"> </span><span class="n">involving</span><span class="w"> </span><span class="n">buf</span><span class="p">...</span>
<span class="n">res</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyBytes_FromString</span><span class="p">(</span><span class="n">buf</span><span class="p">);</span>
<span class="n">free</span><span class="p">(</span><span class="n">buf</span><span class="p">);</span><span class="w"> </span><span class="cm">/* malloc&#39;ed */</span>
<span class="k">return</span><span class="w"> </span><span class="n">res</span><span class="p">;</span>
</pre></div>
</div>
<p>在这个例子中I/O 缓冲区的内存请求是由 C 库分配器处理的。Python 内存管理器只参与了分配作为结果返回的字节对象。</p>
<p>然而,在大多数情况下,建议专门从 Python 堆中分配内存,因为后者由 Python 内存管理器控制。例如,当解释器扩展了用 C 写的新对象类型时,就必须这样做。使用 Python 堆的另一个原因是希望*通知* Python 内存管理器关于扩展模块的内存需求。即使所请求的内存全部只用于内部的、高度特定的目的,将所有的内存请求交给 Python 内存管理器能让解释器对其内存占用的整体情况有更准确的了解。因此在某些情况下Python 内存管理器可能会触发或不触发适当的操作,如垃圾回收、内存压缩或其他预防性操作。请注意,通过使用前面例子中所示的 C 库分配器,为 I/O 缓冲区分配的内存会完全不受 Python 内存管理器管理。</p>
<div class="admonition seealso">
<p class="admonition-title">参见</p>
<p>环境变量 <span class="target" id="index-9"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONMALLOC"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONMALLOC</span></code></a> 可被用来配置 Python 所使用的内存分配器。</p>
<p>环境变量 <span class="target" id="index-10"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONMALLOCSTATS"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONMALLOCSTATS</span></code></a> 可以用来在每次创建和关闭新的 pymalloc 对象区域时打印 <a class="reference internal" href="#pymalloc"><span class="std std-ref">pymalloc 内存分配器</span></a> 的统计数据。</p>
</div>
</section>
<section id="raw-memory-interface">
<h2>原始内存接口<a class="headerlink" href="#raw-memory-interface" title="永久链接至标题"></a></h2>
<p>以下函数集封装了系统分配器。这些函数是线程安全的,不需要持有 <a class="reference internal" href="../glossary.html#term-global-interpreter-lock"><span class="xref std std-term">全局解释器锁</span></a></p>
<p><a class="reference internal" href="#default-memory-allocators"><span class="std std-ref">default raw memory allocator</span></a> 使用这些函数:<code class="xref c c-func docutils literal notranslate"><span class="pre">malloc()</span></code><code class="xref c c-func docutils literal notranslate"><span class="pre">calloc()</span></code><code class="xref c c-func docutils literal notranslate"><span class="pre">realloc()</span></code><code class="xref c c-func docutils literal notranslate"><span class="pre">free()</span></code>;申请零字节时则调用 <code class="docutils literal notranslate"><span class="pre">malloc(1)</span></code> (或 <code class="docutils literal notranslate"><span class="pre">calloc(1,</span> <span class="pre">1)</span></code></p>
<div class="versionadded">
<p><span class="versionmodified added">3.4 新版功能.</span></p>
</div>
<dl class="function">
<dt id="c.PyMem_RawMalloc">
void* <code class="sig-name descname">PyMem_RawMalloc</code><span class="sig-paren">(</span>size_t<em> n</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_RawMalloc" title="永久链接至目标"></a></dt>
<dd><p>分配 <em>n</em> 个字节并返回一个指向分配的内存的 <code class="xref c c-type docutils literal notranslate"><span class="pre">void*</span></code> 类型指针,如果请求失败则返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code></p>
<p>请求零字节可能返回一个独特的非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 指针,就像调用了 <code class="docutils literal notranslate"><span class="pre">PyMem_RawMalloc(1)</span></code> 一样。但是内存不会以任何方式被初始化。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_RawCalloc">
void* <code class="sig-name descname">PyMem_RawCalloc</code><span class="sig-paren">(</span>size_t<em> nelem</em>, size_t<em> elsize</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_RawCalloc" title="永久链接至目标"></a></dt>
<dd><p>分配 <em>nelem</em> 个元素,每个元素的大小为 <em>elsize</em> 字节,并返回指向分配的内存的 <code class="xref c c-type docutils literal notranslate"><span class="pre">void*</span></code> 类型指针,如果请求失败则返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>。 内存会被初始化为零。</p>
<p>请求零字节可能返回一个独特的非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 指针,就像调用了 <code class="docutils literal notranslate"><span class="pre">PyMem_RawCalloc(1,</span> <span class="pre">1)</span></code> 一样。</p>
<div class="versionadded">
<p><span class="versionmodified added">3.5 新版功能.</span></p>
</div>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_RawRealloc">
void* <code class="sig-name descname">PyMem_RawRealloc</code><span class="sig-paren">(</span>void<em> *p</em>, size_t<em> n</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_RawRealloc" title="永久链接至目标"></a></dt>
<dd><p><em>p</em> 指向的内存块大小调整为 <em>n</em> 字节。以新旧内存块大小中的最小值为准,其中内容保持不变,</p>
<p>如果 <em>p</em><code class="docutils literal notranslate"><span class="pre">NULL</span></code> ,则相当于调用 <code class="docutils literal notranslate"><span class="pre">PyMem_RawMalloc(n)</span></code> ;如果 <em>n</em> 等于 0则内存块大小会被调整但不会被释放返回非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 指针。</p>
<p>除非 <em>p</em><code class="docutils literal notranslate"><span class="pre">NULL</span></code> ,否则它必须是之前调用 <a class="reference internal" href="#c.PyMem_RawMalloc" title="PyMem_RawMalloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawMalloc()</span></code></a><a class="reference internal" href="#c.PyMem_RawRealloc" title="PyMem_RawRealloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawRealloc()</span></code></a><a class="reference internal" href="#c.PyMem_RawCalloc" title="PyMem_RawCalloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawCalloc()</span></code></a> 所返回的。</p>
<p>如果请求失败,<a class="reference internal" href="#c.PyMem_RawRealloc" title="PyMem_RawRealloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawRealloc()</span></code></a> 返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> <em>p</em> 仍然是指向先前内存区域的有效指针。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_RawFree">
void <code class="sig-name descname">PyMem_RawFree</code><span class="sig-paren">(</span>void<em> *p</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_RawFree" title="永久链接至目标"></a></dt>
<dd><p>释放 <em>p</em> 指向的内存块。 <em>p</em> 必须是之前调用 <a class="reference internal" href="#c.PyMem_RawMalloc" title="PyMem_RawMalloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawMalloc()</span></code></a><a class="reference internal" href="#c.PyMem_RawRealloc" title="PyMem_RawRealloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawRealloc()</span></code></a><a class="reference internal" href="#c.PyMem_RawCalloc" title="PyMem_RawCalloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawCalloc()</span></code></a> 所返回的指针。否则,或在 <code class="docutils literal notranslate"><span class="pre">PyMem_RawFree(p)</span></code> 之前已经调用过的情况下,未定义的行为会发生。</p>
<p>如果 <em>p</em><code class="docutils literal notranslate"><span class="pre">NULL</span></code>, 那么什么操作也不会进行。</p>
</dd></dl>
</section>
<section id="memory-interface">
<span id="memoryinterface"></span><h2>内存接口<a class="headerlink" href="#memory-interface" title="永久链接至标题"></a></h2>
<p>以下函数集,仿照 ANSI C 标准并指定了请求零字节时的行为可用于从Python堆分配和释放内存。</p>
<p><a class="reference internal" href="#default-memory-allocators"><span class="std std-ref">默认内存分配器</span></a> 使用了 <a class="reference internal" href="#pymalloc"><span class="std std-ref">pymalloc 内存分配器</span></a>.</p>
<div class="admonition warning">
<p class="admonition-title">警告</p>
<p>在使用这些函数时,必须持有 <a class="reference internal" href="../glossary.html#term-global-interpreter-lock"><span class="xref std std-term">全局解释器锁GIL</span></a></p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.6 版更改: </span>现在默认的分配器是 pymalloc 而非系统的 <code class="xref c c-func docutils literal notranslate"><span class="pre">malloc()</span></code></p>
</div>
<dl class="function">
<dt id="c.PyMem_Malloc">
void* <code class="sig-name descname">PyMem_Malloc</code><span class="sig-paren">(</span>size_t<em> n</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_Malloc" title="永久链接至目标"></a></dt>
<dd><p>分配 <em>n</em> 个字节并返回一个指向分配的内存的 <code class="xref c c-type docutils literal notranslate"><span class="pre">void*</span></code> 类型指针,如果请求失败则返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code></p>
<p>请求零字节可能返回一个独特的非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 指针,就像调用了 <code class="docutils literal notranslate"><span class="pre">PyMem_Malloc(1)</span></code> 一样。但是内存不会以任何方式被初始化。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_Calloc">
void* <code class="sig-name descname">PyMem_Calloc</code><span class="sig-paren">(</span>size_t<em> nelem</em>, size_t<em> elsize</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_Calloc" title="永久链接至目标"></a></dt>
<dd><p>分配 <em>nelem</em> 个元素,每个元素的大小为 <em>elsize</em> 字节,并返回指向分配的内存的 <code class="xref c c-type docutils literal notranslate"><span class="pre">void*</span></code> 类型指针,如果请求失败则返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>。 内存会被初始化为零。</p>
<p>请求零字节可能返回一个独特的非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 指针,就像调用了 <code class="docutils literal notranslate"><span class="pre">PyMem_Calloc(1,</span> <span class="pre">1)</span></code> 一样。</p>
<div class="versionadded">
<p><span class="versionmodified added">3.5 新版功能.</span></p>
</div>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_Realloc">
void* <code class="sig-name descname">PyMem_Realloc</code><span class="sig-paren">(</span>void<em> *p</em>, size_t<em> n</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_Realloc" title="永久链接至目标"></a></dt>
<dd><p><em>p</em> 指向的内存块大小调整为 <em>n</em> 字节。以新旧内存块大小中的最小值为准,其中内容保持不变,</p>
<p>如果 <em>p</em><code class="docutils literal notranslate"><span class="pre">NULL</span></code> ,则相当于调用 <code class="docutils literal notranslate"><span class="pre">PyMem_Malloc(n)</span></code> ;如果 <em>n</em> 等于 0则内存块大小会被调整但不会被释放返回非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 指针。</p>
<p>除非 <em>p</em><code class="docutils literal notranslate"><span class="pre">NULL</span></code> ,否则它必须是之前调用 <a class="reference internal" href="#c.PyMem_Malloc" title="PyMem_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Malloc()</span></code></a><a class="reference internal" href="#c.PyMem_Realloc" title="PyMem_Realloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Realloc()</span></code></a><a class="reference internal" href="#c.PyMem_Calloc" title="PyMem_Calloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Calloc()</span></code></a> 所返回的。</p>
<p>如果请求失败,<a class="reference internal" href="#c.PyMem_Realloc" title="PyMem_Realloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Realloc()</span></code></a> 返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> <em>p</em> 仍然是指向先前内存区域的有效指针。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_Free">
void <code class="sig-name descname">PyMem_Free</code><span class="sig-paren">(</span>void<em> *p</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_Free" title="永久链接至目标"></a></dt>
<dd><p>释放 <em>p</em> 指向的内存块。 <em>p</em> 必须是之前调用 <a class="reference internal" href="#c.PyMem_Malloc" title="PyMem_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Malloc()</span></code></a><a class="reference internal" href="#c.PyMem_Realloc" title="PyMem_Realloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Realloc()</span></code></a><a class="reference internal" href="#c.PyMem_Calloc" title="PyMem_Calloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Calloc()</span></code></a> 所返回的指针。否则,或在 <code class="docutils literal notranslate"><span class="pre">PyMem_Free(p)</span></code> 之前已经调用过的情况下,未定义的行为会发生。</p>
<p>如果 <em>p</em><code class="docutils literal notranslate"><span class="pre">NULL</span></code>, 那么什么操作也不会进行。</p>
</dd></dl>
<p>以下面向类型的宏为方便而提供。 注意 <em>TYPE</em> 可以指任何 C 类型。</p>
<dl class="function">
<dt id="c.PyMem_New">
TYPE* <code class="sig-name descname">PyMem_New</code><span class="sig-paren">(</span>TYPE, size_t<em> n</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_New" title="永久链接至目标"></a></dt>
<dd><p><a class="reference internal" href="#c.PyMem_Malloc" title="PyMem_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Malloc()</span></code></a> 相同,但会分配 <code class="docutils literal notranslate"><span class="pre">(n</span> <span class="pre">*</span> <span class="pre">sizeof(TYPE))</span></code> 字节的内存。 返回一个转换为 <code class="xref c c-type docutils literal notranslate"><span class="pre">TYPE*</span></code> 的指针。 内存将不会以任何方式被初始化。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_Resize">
TYPE* <code class="sig-name descname">PyMem_Resize</code><span class="sig-paren">(</span>void<em> *p</em>, TYPE, size_t<em> n</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_Resize" title="永久链接至目标"></a></dt>
<dd><p><a class="reference internal" href="#c.PyMem_Realloc" title="PyMem_Realloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Realloc()</span></code></a> 相同,但内存块的大小被调整为 <code class="docutils literal notranslate"><span class="pre">(n</span> <span class="pre">*</span> <span class="pre">sizeof(TYPE))</span></code> 字节。 返回一个转换为 <code class="xref c c-type docutils literal notranslate"><span class="pre">TYPE*</span></code> 类型的指针。 返回时,<em>p</em> 将为指向新内存区域的指针,如果失败则返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code></p>
<p>这是一个 C 预处理宏, <em>p</em> 总是被重新赋值。请保存 <em>p</em> 的原始值,以避免在处理错误时丢失内存。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_Del">
void <code class="sig-name descname">PyMem_Del</code><span class="sig-paren">(</span>void<em> *p</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_Del" title="永久链接至目标"></a></dt>
<dd><p><a class="reference internal" href="#c.PyMem_Free" title="PyMem_Free"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Free()</span></code></a> 相同</p>
</dd></dl>
<p>此外,我们还提供了以下宏集用于直接调用 Python 内存分配器,而不涉及上面列出的 C API 函数。但是请注意,使用它们并不能保证跨 Python 版本的二进制兼容性,因此在扩展模块被弃用。</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">PyMem_MALLOC(size)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">PyMem_NEW(type,</span> <span class="pre">size)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">PyMem_REALLOC(ptr,</span> <span class="pre">size)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">PyMem_RESIZE(ptr,</span> <span class="pre">type,</span> <span class="pre">size)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">PyMem_FREE(ptr)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">PyMem_DEL(ptr)</span></code></p></li>
</ul>
</section>
<section id="object-allocators">
<h2>对象分配器<a class="headerlink" href="#object-allocators" title="永久链接至标题"></a></h2>
<p>以下函数集,仿照 ANSI C 标准并指定了请求零字节时的行为可用于从Python堆分配和释放内存。</p>
<p><a class="reference internal" href="#default-memory-allocators"><span class="std std-ref">默认对象分配器</span></a> 使用 <a class="reference internal" href="#pymalloc"><span class="std std-ref">pymalloc 内存分配器</span></a>.</p>
<div class="admonition warning">
<p class="admonition-title">警告</p>
<p>在使用这些函数时,必须持有 <a class="reference internal" href="../glossary.html#term-global-interpreter-lock"><span class="xref std std-term">全局解释器锁GIL</span></a></p>
</div>
<dl class="function">
<dt id="c.PyObject_Malloc">
void* <code class="sig-name descname">PyObject_Malloc</code><span class="sig-paren">(</span>size_t<em> n</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyObject_Malloc" title="永久链接至目标"></a></dt>
<dd><p>分配 <em>n</em> 个字节并返回一个指向分配的内存的 <code class="xref c c-type docutils literal notranslate"><span class="pre">void*</span></code> 类型指针,如果请求失败则返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code></p>
<p>请求零字节可能返回一个独特的非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 指针,就像调用了 <code class="docutils literal notranslate"><span class="pre">PyObject_Malloc(1)</span></code> 一样。但是内存不会以任何方式被初始化。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyObject_Calloc">
void* <code class="sig-name descname">PyObject_Calloc</code><span class="sig-paren">(</span>size_t<em> nelem</em>, size_t<em> elsize</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyObject_Calloc" title="永久链接至目标"></a></dt>
<dd><p>分配 <em>nelem</em> 个元素,每个元素的大小为 <em>elsize</em> 字节,并返回指向分配的内存的 <code class="xref c c-type docutils literal notranslate"><span class="pre">void*</span></code> 类型指针,如果请求失败则返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>。 内存会被初始化为零。</p>
<p>请求零字节可能返回一个独特的非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 指针,就像调用了 <code class="docutils literal notranslate"><span class="pre">PyObject_Calloc(1,</span> <span class="pre">1)</span></code> 一样。</p>
<div class="versionadded">
<p><span class="versionmodified added">3.5 新版功能.</span></p>
</div>
</dd></dl>
<dl class="function">
<dt id="c.PyObject_Realloc">
void* <code class="sig-name descname">PyObject_Realloc</code><span class="sig-paren">(</span>void<em> *p</em>, size_t<em> n</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyObject_Realloc" title="永久链接至目标"></a></dt>
<dd><p><em>p</em> 指向的内存块大小调整为 <em>n</em> 字节。以新旧内存块大小中的最小值为准,其中内容保持不变,</p>
<p>如果*p*是 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>,则相当于调用 <code class="docutils literal notranslate"><span class="pre">PyObject_Malloc(n)</span></code> ;如果 <em>n</em> 等于 0则内存块大小会被调整但不会被释放返回非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 指针。</p>
<p>除非 <em>p</em><code class="docutils literal notranslate"><span class="pre">NULL</span></code> ,否则它必须是之前调用 <a class="reference internal" href="#c.PyObject_Malloc" title="PyObject_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Malloc()</span></code></a><a class="reference internal" href="#c.PyObject_Realloc" title="PyObject_Realloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Realloc()</span></code></a><a class="reference internal" href="#c.PyObject_Calloc" title="PyObject_Calloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Calloc()</span></code></a> 所返回的。</p>
<p>如果请求失败,<a class="reference internal" href="#c.PyObject_Realloc" title="PyObject_Realloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Realloc()</span></code></a> 返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> <em>p</em> 仍然是指向先前内存区域的有效指针。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyObject_Free">
void <code class="sig-name descname">PyObject_Free</code><span class="sig-paren">(</span>void<em> *p</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyObject_Free" title="永久链接至目标"></a></dt>
<dd><p>释放 <em>p</em> 指向的内存块。 <em>p</em> 必须是之前调用 <a class="reference internal" href="#c.PyObject_Malloc" title="PyObject_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Malloc()</span></code></a><a class="reference internal" href="#c.PyObject_Realloc" title="PyObject_Realloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Realloc()</span></code></a><a class="reference internal" href="#c.PyObject_Calloc" title="PyObject_Calloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Calloc()</span></code></a> 所返回的指针。否则,或在 <code class="docutils literal notranslate"><span class="pre">PyObject_Free(p)</span></code> 之前已经调用过的情况下,未定义行为会发生。</p>
<p>如果 <em>p</em><code class="docutils literal notranslate"><span class="pre">NULL</span></code>, 那么什么操作也不会进行。</p>
</dd></dl>
</section>
<section id="default-memory-allocators">
<span id="id1"></span><h2>默认内存分配器<a class="headerlink" href="#default-memory-allocators" title="永久链接至标题"></a></h2>
<p>默认内存分配器:</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 28%" />
<col style="width: 18%" />
<col style="width: 16%" />
<col style="width: 19%" />
<col style="width: 18%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>配置</p></th>
<th class="head"><p>名称</p></th>
<th class="head"><p>PyMem_RawMalloc</p></th>
<th class="head"><p>PyMem_Malloc</p></th>
<th class="head"><p>PyObject_Malloc</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>发布版本</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">&quot;pymalloc&quot;</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">malloc</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">pymalloc</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">pymalloc</span></code></p></td>
</tr>
<tr class="row-odd"><td><p>调试构建</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">&quot;pymalloc_debug&quot;</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">malloc</span></code> + debug</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">pymalloc</span></code> + debug</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">pymalloc</span></code> + debug</p></td>
</tr>
<tr class="row-even"><td><p>没有 pymalloc 的发布版本</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">&quot;malloc&quot;</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">malloc</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">malloc</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">malloc</span></code></p></td>
</tr>
<tr class="row-odd"><td><p>没有 pymalloc 的调试构建</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">&quot;malloc_debug&quot;</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">malloc</span></code> + debug</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">malloc</span></code> + debug</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">malloc</span></code> + debug</p></td>
</tr>
</tbody>
</table>
<p>说明:</p>
<ul class="simple">
<li><p>名称: 环境变量 <span class="target" id="index-11"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONMALLOC"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONMALLOC</span></code></a> 的值</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">malloc</span></code>: 来自 C 标准库的系统分配, C 函数 <code class="xref c c-func docutils literal notranslate"><span class="pre">malloc()</span></code>, <code class="xref c c-func docutils literal notranslate"><span class="pre">calloc()</span></code>, <code class="xref c c-func docutils literal notranslate"><span class="pre">realloc()</span></code> and <code class="xref c c-func docutils literal notranslate"><span class="pre">free()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pymalloc</span></code>: <a class="reference internal" href="#pymalloc"><span class="std std-ref">pymalloc 内存分配器</span></a></p></li>
<li><p>&quot;+ debug&quot;: 带有 <a class="reference internal" href="#c.PyMem_SetupDebugHooks" title="PyMem_SetupDebugHooks"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_SetupDebugHooks()</span></code></a> 安装的调试钩子</p></li>
</ul>
</section>
<section id="customize-memory-allocators">
<h2>自定义内存分配器<a class="headerlink" href="#customize-memory-allocators" title="永久链接至标题"></a></h2>
<div class="versionadded">
<p><span class="versionmodified added">3.4 新版功能.</span></p>
</div>
<dl class="type">
<dt id="c.PyMemAllocatorEx">
<code class="sig-name descname">PyMemAllocatorEx</code><a class="headerlink" href="#c.PyMemAllocatorEx" title="永久链接至目标"></a></dt>
<dd><p>用于描述内存块分配器的结构体。包含四个字段:</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 60%" />
<col style="width: 40%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p></p></th>
<th class="head"><p>含意</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">void</span> <span class="pre">*ctx</span></code></p></td>
<td><p>作为第一个参数传入的用户上下文</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">void*</span> <span class="pre">malloc(void</span> <span class="pre">*ctx,</span> <span class="pre">size_t</span> <span class="pre">size)</span></code></p></td>
<td><p>分配一个内存块</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">void*</span> <span class="pre">calloc(void</span> <span class="pre">*ctx,</span> <span class="pre">size_t</span> <span class="pre">nelem,</span> <span class="pre">size_t</span> <span class="pre">elsize)</span></code></p></td>
<td><p>分配一个初始化为 0 的内存块</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">void*</span> <span class="pre">realloc(void</span> <span class="pre">*ctx,</span> <span class="pre">void</span> <span class="pre">*ptr,</span> <span class="pre">size_t</span> <span class="pre">new_size)</span></code></p></td>
<td><p>分配一个内存块或调整其大小</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">void</span> <span class="pre">free(void</span> <span class="pre">*ctx,</span> <span class="pre">void</span> <span class="pre">*ptr)</span></code></p></td>
<td><p>释放一个内存块</p></td>
</tr>
</tbody>
</table>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.5 版更改: </span>The <code class="xref c c-type docutils literal notranslate"><span class="pre">PyMemAllocator</span></code> structure was renamed to
<a class="reference internal" href="#c.PyMemAllocatorEx" title="PyMemAllocatorEx"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyMemAllocatorEx</span></code></a> and a new <code class="docutils literal notranslate"><span class="pre">calloc</span></code> field was added.</p>
</div>
</dd></dl>
<dl class="type">
<dt id="c.PyMemAllocatorDomain">
<code class="sig-name descname">PyMemAllocatorDomain</code><a class="headerlink" href="#c.PyMemAllocatorDomain" title="永久链接至目标"></a></dt>
<dd><p>用来识别分配器域的枚举类。域有:</p>
<dl class="macro">
<dt id="c.PYMEM_DOMAIN_RAW">
<code class="sig-name descname">PYMEM_DOMAIN_RAW</code><a class="headerlink" href="#c.PYMEM_DOMAIN_RAW" title="永久链接至目标"></a></dt>
<dd><p>函数</p>
<ul class="simple">
<li><p><a class="reference internal" href="#c.PyMem_RawMalloc" title="PyMem_RawMalloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawMalloc()</span></code></a></p></li>
<li><p><a class="reference internal" href="#c.PyMem_RawRealloc" title="PyMem_RawRealloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawRealloc()</span></code></a></p></li>
<li><p><a class="reference internal" href="#c.PyMem_RawCalloc" title="PyMem_RawCalloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawCalloc()</span></code></a></p></li>
<li><p><a class="reference internal" href="#c.PyMem_RawFree" title="PyMem_RawFree"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawFree()</span></code></a></p></li>
</ul>
</dd></dl>
<dl class="macro">
<dt id="c.PYMEM_DOMAIN_MEM">
<code class="sig-name descname">PYMEM_DOMAIN_MEM</code><a class="headerlink" href="#c.PYMEM_DOMAIN_MEM" title="永久链接至目标"></a></dt>
<dd><p>函数</p>
<ul class="simple">
<li><p><a class="reference internal" href="#c.PyMem_Malloc" title="PyMem_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Malloc()</span></code></a>,</p></li>
<li><p><a class="reference internal" href="#c.PyMem_Realloc" title="PyMem_Realloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Realloc()</span></code></a></p></li>
<li><p><a class="reference internal" href="#c.PyMem_Calloc" title="PyMem_Calloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Calloc()</span></code></a></p></li>
<li><p><a class="reference internal" href="#c.PyMem_Free" title="PyMem_Free"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Free()</span></code></a></p></li>
</ul>
</dd></dl>
<dl class="macro">
<dt id="c.PYMEM_DOMAIN_OBJ">
<code class="sig-name descname">PYMEM_DOMAIN_OBJ</code><a class="headerlink" href="#c.PYMEM_DOMAIN_OBJ" title="永久链接至目标"></a></dt>
<dd><p>函数</p>
<ul class="simple">
<li><p><a class="reference internal" href="#c.PyObject_Malloc" title="PyObject_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Malloc()</span></code></a></p></li>
<li><p><a class="reference internal" href="#c.PyObject_Realloc" title="PyObject_Realloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Realloc()</span></code></a></p></li>
<li><p><a class="reference internal" href="#c.PyObject_Calloc" title="PyObject_Calloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Calloc()</span></code></a></p></li>
<li><p><a class="reference internal" href="#c.PyObject_Free" title="PyObject_Free"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Free()</span></code></a></p></li>
</ul>
</dd></dl>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_GetAllocator">
void <code class="sig-name descname">PyMem_GetAllocator</code><span class="sig-paren">(</span><a class="reference internal" href="#c.PyMemAllocatorDomain" title="PyMemAllocatorDomain">PyMemAllocatorDomain</a><em> domain</em>, <a class="reference internal" href="#c.PyMemAllocatorEx" title="PyMemAllocatorEx">PyMemAllocatorEx</a><em> *allocator</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_GetAllocator" title="永久链接至目标"></a></dt>
<dd><p>获取指定域的内存块分配器。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_SetAllocator">
void <code class="sig-name descname">PyMem_SetAllocator</code><span class="sig-paren">(</span><a class="reference internal" href="#c.PyMemAllocatorDomain" title="PyMemAllocatorDomain">PyMemAllocatorDomain</a><em> domain</em>, <a class="reference internal" href="#c.PyMemAllocatorEx" title="PyMemAllocatorEx">PyMemAllocatorEx</a><em> *allocator</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_SetAllocator" title="永久链接至目标"></a></dt>
<dd><p>设置指定域的内存块分配器。</p>
<p>当请求零字节时,新的分配器必须返回一个独特的非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 指针。</p>
<p>对于 <a class="reference internal" href="#c.PYMEM_DOMAIN_RAW" title="PYMEM_DOMAIN_RAW"><code class="xref c c-data docutils literal notranslate"><span class="pre">PYMEM_DOMAIN_RAW</span></code></a> 域,分配器必须是线程安全的:当分配器被调用时,不持有 <a class="reference internal" href="../glossary.html#term-global-interpreter-lock"><span class="xref std std-term">全局解释器锁</span></a></p>
<p>如果新的分配器不是钩子(不调用之前的分配器),必须调用 <a class="reference internal" href="#c.PyMem_SetupDebugHooks" title="PyMem_SetupDebugHooks"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_SetupDebugHooks()</span></code></a> 函数在新分配器上重新安装调试钩子。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyMem_SetupDebugHooks">
void <code class="sig-name descname">PyMem_SetupDebugHooks</code><span class="sig-paren">(</span>void<span class="sig-paren">)</span><a class="headerlink" href="#c.PyMem_SetupDebugHooks" title="永久链接至目标"></a></dt>
<dd><p>设置检测 Python 内存分配器函数中错误的钩子。</p>
<p>新分配的内存由字节 <code class="docutils literal notranslate"><span class="pre">0xCD</span></code> ( <code class="docutils literal notranslate"><span class="pre">CLEANBYTE</span></code> ) 填充,释放的内存由字节 <code class="docutils literal notranslate"><span class="pre">0xDD</span></code> ( <code class="docutils literal notranslate"><span class="pre">DEADBYTE</span></code> )填充。内存块被 &quot;禁止字节&quot; 包围( <code class="docutils literal notranslate"><span class="pre">FORBIDDENBYTE</span></code> :字节 <code class="docutils literal notranslate"><span class="pre">0xFD</span></code> )。</p>
<p>运行时检查:</p>
<ul class="simple">
<li><p>检测对 API 的违反,例如:对用 <a class="reference internal" href="#c.PyMem_Malloc" title="PyMem_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Malloc()</span></code></a> 分配的缓冲区调用 <a class="reference internal" href="#c.PyObject_Free" title="PyObject_Free"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Free()</span></code></a></p></li>
<li><p>检测缓冲区起始位置前的写入(缓冲区下溢)。</p></li>
<li><p>检测缓冲区终止位置后的写入(缓冲区溢出)。</p></li>
<li><p>检测当调用 <a class="reference internal" href="#c.PYMEM_DOMAIN_OBJ" title="PYMEM_DOMAIN_OBJ"><code class="xref c c-data docutils literal notranslate"><span class="pre">PYMEM_DOMAIN_OBJ</span></code></a> (如: <a class="reference internal" href="#c.PyObject_Malloc" title="PyObject_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Malloc()</span></code></a>) 和 <a class="reference internal" href="#c.PYMEM_DOMAIN_MEM" title="PYMEM_DOMAIN_MEM"><code class="xref c c-data docutils literal notranslate"><span class="pre">PYMEM_DOMAIN_MEM</span></code></a> (如: <a class="reference internal" href="#c.PyMem_Malloc" title="PyMem_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Malloc()</span></code></a>) 域的分配器函数时 <a class="reference internal" href="../glossary.html#term-global-interpreter-lock"><span class="xref std std-term">GIL</span></a> 已被保持。</p></li>
</ul>
<p>在出错时,调试钩子使用 <a class="reference internal" href="../library/tracemalloc.html#module-tracemalloc" title="tracemalloc: Trace memory allocations."><code class="xref py py-mod docutils literal notranslate"><span class="pre">tracemalloc</span></code></a> 模块来回溯内存块被分配的位置。只有当 <a class="reference internal" href="../library/tracemalloc.html#module-tracemalloc" title="tracemalloc: Trace memory allocations."><code class="xref py py-mod docutils literal notranslate"><span class="pre">tracemalloc</span></code></a> 正在追踪 Python 内存分配,并且内存块被追踪时,才会显示回溯。</p>
<p>如果 Python 是在调试模式下编译的,这些钩子是 <a class="reference internal" href="#default-memory-allocators"><span class="std std-ref">installed by default</span></a> 。环境变量 <span class="target" id="index-12"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONMALLOC"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONMALLOC</span></code></a> 可以用来在发布模式编译的 Python 上安装调试钩子。</p>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.6 版更改: </span>这个函数现在也适用于以 发布模式编译的 Python。在出错时调试钩子现在使用 <a class="reference internal" href="../library/tracemalloc.html#module-tracemalloc" title="tracemalloc: Trace memory allocations."><code class="xref py py-mod docutils literal notranslate"><span class="pre">tracemalloc</span></code></a> 来回溯内存块被分配的位置。调试钩子现在也检查当 <a class="reference internal" href="#c.PYMEM_DOMAIN_OBJ" title="PYMEM_DOMAIN_OBJ"><code class="xref c c-data docutils literal notranslate"><span class="pre">PYMEM_DOMAIN_OBJ</span></code></a><a class="reference internal" href="#c.PYMEM_DOMAIN_MEM" title="PYMEM_DOMAIN_MEM"><code class="xref c c-data docutils literal notranslate"><span class="pre">PYMEM_DOMAIN_MEM</span></code></a> 域的函数被调用时,全局解释器锁是否被持有。</p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">在 3.8 版更改: </span>字节模式 <code class="docutils literal notranslate"><span class="pre">0xCB</span></code> (<code class="docutils literal notranslate"><span class="pre">CLEANBYTE</span></code>)、 <code class="docutils literal notranslate"><span class="pre">0xDB</span></code> (<code class="docutils literal notranslate"><span class="pre">DEADBYTE</span></code>) 和 <code class="docutils literal notranslate"><span class="pre">0xFB</span></code> (<code class="docutils literal notranslate"><span class="pre">FORBIDDENBYTE</span></code>) 已被 <code class="docutils literal notranslate"><span class="pre">0xCD</span></code><code class="docutils literal notranslate"><span class="pre">0xDD</span></code><code class="docutils literal notranslate"><span class="pre">0xFD</span></code> 替代以使用与 Windows CRT 调试 <code class="docutils literal notranslate"><span class="pre">malloc()</span></code><code class="docutils literal notranslate"><span class="pre">free()</span></code> 相同的值。</p>
</div>
</dd></dl>
</section>
<section id="the-pymalloc-allocator">
<span id="pymalloc"></span><h2>pymalloc 分配器<a class="headerlink" href="#the-pymalloc-allocator" title="永久链接至标题"></a></h2>
<p>Python 有为具有短生命周期的小对象(小于或等于 512 字节)优化的 <em>pymalloc</em> 分配器。它使用固定大小为 256 KiB 的称为 &quot;arenas&quot; 的内存映射。对于大于512字节的分配它回到使用 <a class="reference internal" href="#c.PyMem_RawMalloc" title="PyMem_RawMalloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawMalloc()</span></code></a><a class="reference internal" href="#c.PyMem_RawRealloc" title="PyMem_RawRealloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_RawRealloc()</span></code></a></p>
<p><em>pymalloc</em><a class="reference internal" href="#c.PYMEM_DOMAIN_MEM" title="PYMEM_DOMAIN_MEM"><code class="xref c c-data docutils literal notranslate"><span class="pre">PYMEM_DOMAIN_MEM</span></code></a> (例如: <a class="reference internal" href="#c.PyMem_Malloc" title="PyMem_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyMem_Malloc()</span></code></a>) 和 <a class="reference internal" href="#c.PYMEM_DOMAIN_OBJ" title="PYMEM_DOMAIN_OBJ"><code class="xref c c-data docutils literal notranslate"><span class="pre">PYMEM_DOMAIN_OBJ</span></code></a> (例如: <a class="reference internal" href="#c.PyObject_Malloc" title="PyObject_Malloc"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Malloc()</span></code></a>) 域的 <a class="reference internal" href="#default-memory-allocators"><span class="std std-ref">默认分配器</span></a></p>
<p>arena 分配器使用以下函数:</p>
<ul class="simple">
<li><p>Windows 上的 <code class="xref c c-func docutils literal notranslate"><span class="pre">VirtualAlloc()</span></code><code class="xref c c-func docutils literal notranslate"><span class="pre">VirtualFree()</span></code> ,</p></li>
<li><p><code class="xref c c-func docutils literal notranslate"><span class="pre">mmap()</span></code><code class="xref c c-func docutils literal notranslate"><span class="pre">munmap()</span></code> ,如果可用,</p></li>
<li><p>否则, <code class="xref c c-func docutils literal notranslate"><span class="pre">malloc()</span></code><code class="xref c c-func docutils literal notranslate"><span class="pre">free()</span></code></p></li>
</ul>
<section id="customize-pymalloc-arena-allocator">
<h3>自定义 pymalloc Arena 分配器<a class="headerlink" href="#customize-pymalloc-arena-allocator" title="永久链接至标题"></a></h3>
<div class="versionadded">
<p><span class="versionmodified added">3.4 新版功能.</span></p>
</div>
<dl class="type">
<dt id="c.PyObjectArenaAllocator">
<code class="sig-name descname">PyObjectArenaAllocator</code><a class="headerlink" href="#c.PyObjectArenaAllocator" title="永久链接至目标"></a></dt>
<dd><p>用来描述一个 arena 分配器的结构体。这个结构体有三个字段:</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 56%" />
<col style="width: 44%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p></p></th>
<th class="head"><p>含意</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">void</span> <span class="pre">*ctx</span></code></p></td>
<td><p>作为第一个参数传入的用户上下文</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">void*</span> <span class="pre">alloc(void</span> <span class="pre">*ctx,</span> <span class="pre">size_t</span> <span class="pre">size)</span></code></p></td>
<td><p>分配一块 size 字节的区域</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">void</span> <span class="pre">free(void</span> <span class="pre">*ctx,</span> <span class="pre">void</span> <span class="pre">*ptr,</span> <span class="pre">size_t</span> <span class="pre">size)</span></code></p></td>
<td><p>释放一块区域</p></td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="function">
<dt id="c.PyObject_GetArenaAllocator">
void <code class="sig-name descname">PyObject_GetArenaAllocator</code><span class="sig-paren">(</span><a class="reference internal" href="#c.PyObjectArenaAllocator" title="PyObjectArenaAllocator">PyObjectArenaAllocator</a><em> *allocator</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyObject_GetArenaAllocator" title="永久链接至目标"></a></dt>
<dd><p>获取 arena 分配器</p>
</dd></dl>
<dl class="function">
<dt id="c.PyObject_SetArenaAllocator">
void <code class="sig-name descname">PyObject_SetArenaAllocator</code><span class="sig-paren">(</span><a class="reference internal" href="#c.PyObjectArenaAllocator" title="PyObjectArenaAllocator">PyObjectArenaAllocator</a><em> *allocator</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyObject_SetArenaAllocator" title="永久链接至目标"></a></dt>
<dd><p>设置 arena 分配器</p>
</dd></dl>
</section>
</section>
<section id="tracemalloc-c-api">
<h2>tracemalloc C API<a class="headerlink" href="#tracemalloc-c-api" title="永久链接至标题"></a></h2>
<div class="versionadded">
<p><span class="versionmodified added">3.7 新版功能.</span></p>
</div>
<dl class="function">
<dt id="c.PyTraceMalloc_Track">
int <code class="sig-name descname">PyTraceMalloc_Track</code><span class="sig-paren">(</span>unsigned int<em> domain</em>, uintptr_t<em> ptr</em>, size_t<em> size</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyTraceMalloc_Track" title="永久链接至目标"></a></dt>
<dd><p><a class="reference internal" href="../library/tracemalloc.html#module-tracemalloc" title="tracemalloc: Trace memory allocations."><code class="xref py py-mod docutils literal notranslate"><span class="pre">tracemalloc</span></code></a> 模块中跟踪一个已分配的内存块。</p>
<p>成功时返回 <code class="docutils literal notranslate"><span class="pre">0</span></code>,出错时返回 <code class="docutils literal notranslate"><span class="pre">-1</span></code> (无法分配内存来保存跟踪信息)。 如果禁用了 tracemalloc 则返回 <code class="docutils literal notranslate"><span class="pre">-2</span></code></p>
<p>如果内存块已被跟踪,则更新现有跟踪信息。</p>
</dd></dl>
<dl class="function">
<dt id="c.PyTraceMalloc_Untrack">
int <code class="sig-name descname">PyTraceMalloc_Untrack</code><span class="sig-paren">(</span>unsigned int<em> domain</em>, uintptr_t<em> ptr</em><span class="sig-paren">)</span><a class="headerlink" href="#c.PyTraceMalloc_Untrack" title="永久链接至目标"></a></dt>
<dd><p><a class="reference internal" href="../library/tracemalloc.html#module-tracemalloc" title="tracemalloc: Trace memory allocations."><code class="xref py py-mod docutils literal notranslate"><span class="pre">tracemalloc</span></code></a> 模块中取消跟踪一个已分配的内存块。 如果内存块未被跟踪则不执行任何操作。</p>
<p>如果 tracemalloc 被禁用则返回 <code class="docutils literal notranslate"><span class="pre">-2</span></code>,否则返回 <code class="docutils literal notranslate"><span class="pre">0</span></code></p>
</dd></dl>
</section>
<section id="examples">
<span id="memoryexamples"></span><h2>例子<a class="headerlink" href="#examples" title="永久链接至标题"></a></h2>
<p>以下是来自 <a class="reference internal" href="#memoryoverview"><span class="std std-ref">概述</span></a> 小节的示例,经过重写以使 I/O 缓冲区是通过使用第一个函数集从 Python 堆中分配的:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">res</span><span class="p">;</span>
<span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">buf</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">PyMem_Malloc</span><span class="p">(</span><span class="n">BUFSIZ</span><span class="p">);</span><span class="w"> </span><span class="cm">/* for I/O */</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">PyErr_NoMemory</span><span class="p">();</span>
<span class="cm">/* ...Do some I/O operation involving buf... */</span>
<span class="n">res</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyBytes_FromString</span><span class="p">(</span><span class="n">buf</span><span class="p">);</span>
<span class="n">PyMem_Free</span><span class="p">(</span><span class="n">buf</span><span class="p">);</span><span class="w"> </span><span class="cm">/* allocated with PyMem_Malloc */</span>
<span class="k">return</span><span class="w"> </span><span class="n">res</span><span class="p">;</span>
</pre></div>
</div>
<p>使用面向类型函数集的相同代码:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">res</span><span class="p">;</span>
<span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">buf</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyMem_New</span><span class="p">(</span><span class="kt">char</span><span class="p">,</span><span class="w"> </span><span class="n">BUFSIZ</span><span class="p">);</span><span class="w"> </span><span class="cm">/* for I/O */</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">PyErr_NoMemory</span><span class="p">();</span>
<span class="cm">/* ...Do some I/O operation involving buf... */</span>
<span class="n">res</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyBytes_FromString</span><span class="p">(</span><span class="n">buf</span><span class="p">);</span>
<span class="n">PyMem_Del</span><span class="p">(</span><span class="n">buf</span><span class="p">);</span><span class="w"> </span><span class="cm">/* allocated with PyMem_New */</span>
<span class="k">return</span><span class="w"> </span><span class="n">res</span><span class="p">;</span>
</pre></div>
</div>
<p>请注意在以上两个示例中,缓冲区总是通过归属于相同集的函数来操纵的。 事实上,对于一个给定的内存块必须使用相同的内存 API 族,以便使得混合不同分配器的风险减至最低。 以下代码序列包含两处错误,其中一个被标记为 <em>fatal</em> 因为它混合了两种在不同堆上操作的不同分配器。</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">buf1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyMem_New</span><span class="p">(</span><span class="kt">char</span><span class="p">,</span><span class="w"> </span><span class="n">BUFSIZ</span><span class="p">);</span>
<span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">buf2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">malloc</span><span class="p">(</span><span class="n">BUFSIZ</span><span class="p">);</span>
<span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">buf3</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">PyMem_Malloc</span><span class="p">(</span><span class="n">BUFSIZ</span><span class="p">);</span>
<span class="p">...</span>
<span class="n">PyMem_Del</span><span class="p">(</span><span class="n">buf3</span><span class="p">);</span><span class="w"> </span><span class="cm">/* Wrong -- should be PyMem_Free() */</span>
<span class="n">free</span><span class="p">(</span><span class="n">buf2</span><span class="p">);</span><span class="w"> </span><span class="cm">/* Right -- allocated via malloc() */</span>
<span class="n">free</span><span class="p">(</span><span class="n">buf1</span><span class="p">);</span><span class="w"> </span><span class="cm">/* Fatal -- should be PyMem_Del() */</span>
</pre></div>
</div>
<p>除了旨在处理来自 Python 堆的原始内存块的函数之外, Python 中的对象是通过 <a class="reference internal" href="allocation.html#c.PyObject_New" title="PyObject_New"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_New()</span></code></a>, <a class="reference internal" href="allocation.html#c.PyObject_NewVar" title="PyObject_NewVar"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_NewVar()</span></code></a><a class="reference internal" href="allocation.html#c.PyObject_Del" title="PyObject_Del"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_Del()</span></code></a> 来分配和释放的。</p>
<p>这些将在有关如何在 C 中定义和实现新对象类型的下一章中讲解。</p>
</section>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h3><a href="../contents.html">目录</a></h3>
<ul>
<li><a class="reference internal" href="#">内存管理</a><ul>
<li><a class="reference internal" href="#overview">概述</a></li>
<li><a class="reference internal" href="#raw-memory-interface">原始内存接口</a></li>
<li><a class="reference internal" href="#memory-interface">内存接口</a></li>
<li><a class="reference internal" href="#object-allocators">对象分配器</a></li>
<li><a class="reference internal" href="#default-memory-allocators">默认内存分配器</a></li>
<li><a class="reference internal" href="#customize-memory-allocators">自定义内存分配器</a></li>
<li><a class="reference internal" href="#the-pymalloc-allocator">pymalloc 分配器</a><ul>
<li><a class="reference internal" href="#customize-pymalloc-arena-allocator">自定义 pymalloc Arena 分配器</a></li>
</ul>
</li>
<li><a class="reference internal" href="#tracemalloc-c-api">tracemalloc C API</a></li>
<li><a class="reference internal" href="#examples">例子</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="init_config.html"
title="上一章">Python初始化配置</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="objimpl.html"
title="下一章">对象实现支持</a></p>
<div role="note" aria-label="source link">
<h3>本页</h3>
<ul class="this-page-menu">
<li><a href="../bugs.html">报告 Bug</a></li>
<li>
<a href="https://github.com/python/cpython/blob/3.8/Doc/c-api/memory.rst"
rel="nofollow">显示源代码
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>导航</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="总目录"
>索引</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python 模块索引"
>模块</a> |</li>
<li class="right" >
<a href="objimpl.html" title="对象实现支持"
>下一页</a> |</li>
<li class="right" >
<a href="init_config.html" title="Python初始化配置"
>上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >Python/C API 参考手册</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="footer">
&copy; <a href="../copyright.html">版权所有</a> 2001-2024, Python Software Foundation.
<br />
This page is licensed under the Python Software Foundation License Version 2.
<br />
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
<br />
<br />
The Python Software Foundation is a non-profit corporation.
<a href="https://www.python.org/psf/donations/">Please donate.</a>
<br />
<br />
最后更新于 12月 09, 2024.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 2.4.4.
</div>
</body>
</html>