CPython 跨解释器共享 memoryview 时内存不足崩溃的修复:正确抛出 MemoryError

发布时间:2026/9/10 3:07:55
CPython 跨解释器共享 memoryview 时内存不足崩溃的修复:正确抛出 MemoryError CPython 跨解释器共享 memoryview 时内存不足崩溃的修复正确抛出 MemoryError【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython本篇文章聚焦 CPython 主线仓库中的一项具体缺陷修复当memoryview对象在子解释器subinterpreters之间共享、且底层内存分配失败内存不足时原本可能导致解释器崩溃crash现在改为正确地抛出MemoryError异常。文章将结合 修复记录 与 核心实现 的源码讲解共享机制的内部原理、崩溃根因以及修复后的行为帮助读者理解 CPython 在跨解释器对象共享cross-interpreter sharing场景下的内存管理细节。修复记录原文本次修复对应的变更记录位于 Misc/NEWS.d/next/Core_and_Builtins/2026-06-18-16-00-10.gh-issue-151126.tBqn6I.rst归属类别为Core_and_Builtins关联 issue 编号为gh-issue-151126。原文内容如下Fix a crash when sharingmemoryviewobjects between interpreters fails due to running out of memory. It now raises a properMemoryError.翻译过来即修复在解释器之间共享memoryview对象时因内存不足而导致共享失败并引发崩溃的问题。现在该场景会正确抛出MemoryError异常。这则记录的新闻碎片文件NEWS fragment说明了两件事旧行为Bug在跨解释器共享memoryview时如果内存分配失败解释器会直接崩溃crash而不是返回错误新行为修复后同一场景下CPython 会抛出标准的MemoryError异常让上层代码可以捕获并处理。背景为什么 memoryview 可以在解释器之间共享子解释器与对象共享机制CPython 支持在同一个进程内创建多个相互隔离的子解释器subinterpreters相关能力由_interpreters扩展模块暴露实现在 Modules/_interpretersmodule.c 中。每个解释器拥有独立的执行状态与命名空间默认情况下对象不能在解释器之间直接传递。不过对于某些数据类型CPython 提供了**跨解释器共享cross-interpreter sharing**能力即通过_interpreters.run_string()、_interpreters.exec()等入口的shared参数将对象传入另一个解释器。可共享对象必须是可共享类型shareable types。memoryview正是这类可共享对象之一。源码注释Modules/_interpretersmodule.c 第 98126 行明确解释了其设计意图When a memoryview object is shared between interpreters, its underlying buffer memory is actually shared, rather than just copied. This facilitates efficient use of that data where otherwise interpreters are strictly isolated.也就是说共享memoryview时其底层的缓冲区内存是真正共享的而不是拷贝一份从而在解释器严格隔离的前提下实现了对同一块数据的高效访问。共享背后的数据流从源码结构看共享memoryview的核心流程分为两段发送侧源解释器类型注册回调_pybuffer_shared()Modules/_interpretersmodule.c 第 275295 行负责在共享时通过PyObject_GetBuffer(obj, view-view, PyBUF_FULL_RO)以只读模式获取底层Py_buffer并把该 buffer 打包进跨解释器数据_PyXIData_t中。源码注释特别指出这一步会让 memoryview 的导出计数export count增加直到另一端释放视图后才会递减接收侧目标解释器回调_memoryview_from_xid()第 237263 行把传来的Py_buffer包装进一个特殊的xibufferview对象再通过PyMemoryView_FromObject(obj)在目标解释器中重建出一个新的memoryview。其中xibufferview第 134138 行定义包含Py_buffer *view与int64_t interpid是一个跨解释器安全的缓冲包装对象它的存在是为了解决一个隔离性难题如果直接让目标解释器中的Py_buffer.obj指向源解释器的原始 memoryview那么释放 bufferPyBuffer_Release()就会发生在错误的解释器上下文中破坏解释器隔离。因此xibufferview_getbuf()第 199211 行会把view-obj指向这个包装对象本身由xibufferview_dealloc()第 166197 行负责在正确的解释器通过interpid查找中释放原始 buffer。崩溃根因分析分配失败路径上的错误处理缺口在修复之前跨解释器共享memoryview的路径上有若干处内存分配调用其中部分失败路径没有正确地向调用方传播错误而是直接返回了空指针或无效状态最终导致解释器崩溃。从当前源码看与本次修复相关的关键分配点集中在xibufferview的创建过程中xibufferview_from_buffer()Modules/_interpretersmodule.c 第 140164 行中先通过PyMem_RawMalloc(sizeof(Py_buffer))拷贝一份Py_buffer结构再用PyObject_Malloc(sizeof(xibufferview))为包装对象分配内存。这两处分配若失败代码会分别调用PyErr_NoMemory()并返回NULL第 146156 行注意第二处失败时还会先用PyMem_RawFree(copied)释放已拷贝的 buffer避免内存泄漏随后在_memoryview_from_xid()第 237263 行中若xibufferview_from_buffer()或PyMemoryView_FromObject(obj)返回NULL外层会通过Py_DECREF(obj)清理并向上返回NULL。结合修复记录中现在会正确抛出MemoryError的表述可以推断修复的实质就是补齐这些失败路径上的错误传播——把分配失败返回空指针、未被识别为错误而继续执行的路径改为统一通过PyErr_NoMemory()设置MemoryError异常并干净地向上返回错误码。这一点与 CPython 的通用约定一致所有PyMem_*/PyObject_*分配函数失败时返回NULL调用方必须检查返回值并设置内存异常典型做法即PyErr_NoMemory()。类似的内存不足错误处理模式在该模块中并不罕见例如_pybuffer_shared()第 278282 行对struct xibuffer分配的失败处理PyMem_RawMalloc返回NULL时调用PyErr_NoMemory()并返回-1就体现了同一约定。修复后的行为与验证方式修复完成后跨解释器共享memoryview时的失败语义与 CPython 其余部分保持一致成功路径共享照常进行目标解释器获得一个指向同一块底层缓冲的只读memoryview失败路径内存不足不再触发崩溃而是向调用方抛出MemoryErrorPython 层代码可以用常规的try/except MemoryError捕获处理。要亲手复现或验证这一行为需要构建一个启用了子解释器共享支持的 CPython该能力由_interpreters模块提供属于实验性特性然后大致按以下方式构造场景import _interpreters # 创建源 memoryview例如基于一个 bytearray buf bytearray(1024 * 1024) mv memoryview(buf) # 在子解释器中运行代码并共享该 memoryview interp _interpreters.create() _interpreters.run_string( interp, import _interpreters; print(shared ok), shared{view: mv}, )在内存不足的极端条件下例如通过资源限制工具或填充内存来压低可用内存修复前该调用可能使进程崩溃修复后则应以MemoryError的形式报错退出进程保持稳定。注意事项与已知边界阅读源码时还应注意到跨解释器共享memoryview目前仍有若干尚未完全解决的边界问题源码中以XXX注释明确标注Modules/_interpretersmodule.c 第 128132 行Note that there is still an issue to sort out, where the original interpreter is destroyed but code in another interpreter is still using dependent buffers. Using such buffers segfaults. This will require a careful fix. In the meantime, users will have to be diligent about avoiding the problematic situation.即如果源解释器先被销毁而其他解释器仍在通过共享的memoryview使用其依赖的缓冲区则访问这些缓冲区仍可能导致段错误segfault。这是一个需要后续谨慎修复的已知问题目前用户需要自行规避源解释器销毁后继续使用共享缓冲这一危险场景。另外由于底层数据是真正共享的多解释器并发访问同一块内存时会涉及线程安全问题源码注释同样强调 the underlying data is subject to the complexities of thread-safety, which the user must manage carefully使用方必须自行做好同步控制。小结维度修复前修复后共享 memoryview 时内存不足解释器崩溃crash抛出MemoryError错误传播分配失败路径未正确上报通过PyErr_NoMemory()设置异常并返回错误用户可处理性无法捕获进程直接异常终止可用try/except MemoryError捕获本次修复是 CPythonCore_and_Builtins领域的一次典型健壮性改进它不改变共享memoryview的正常使用方式只把一条本应报错却直接崩溃的路径修正为符合 CPython 异常语义的MemoryError。对于希望深入理解子解释器对象共享机制的读者建议从 Modules/_interpretersmodule.c 第 98319 行的Cross-interpreter Buffer Views代码段入手再结合 Lib/test/test__interpreters.py 中IsShareableTests等测试类理解可共享对象的判定与传递规则。【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询