Python多进程间使用共享内存会提前释放的问题

问题参考

bugs.python.org/issue38119

问题描述

该问题仅在Unix系统下出现,初步验证可能是和 fork 的进程启动方式有关。

Python 需要通过使用多进程来实现并发,多进程间进行数据交互时共享内存可以节省很多资源,提升数据传输效率。

但如果进程间不是父子进程或有继承关系,那么在通过共享内存传输数据时通常会遇到这种情景:

A进程创建了共享内存块,存入数据后将内存块的 shared_name 传递给B进程,B进程在取出内存中的数据后释放该内存块。C 进程再想获得内存块中的数据但内存块已经被释放。

python 复制代码
from multiprocessing import Pool, shared_memory
import time
import cv2
import numpy as np


def func(sm_name, sha):
    shm = shared_memory.SharedMemory(name=sm_name)
    img = np.nrdarray(sha, np.uint8, shm.buf)

    import time
    cv2.imwrite(str(time.time()) + ".jpg", img)


if __name__ == "__main__":
    p = Pool(2)
    a = cv2.imread("1.jpg")
    shape = a.shape
    s = int(np.prod(shape) * np.dtype(np.uint8).itemsize)
  
    sm = shared_memory.SharedMemory(name="test", create=True, size=s)
    smb = np.ndarray(shape, np.uint8, sm.buf)
    smb[:] = a
    for i in range(10):
        p.starmap(func, [("test", shape), ])
    p.close()
    p.join()
    sm.close()
    sm.unlink()

上述代码在 Windows 下可以运行,在 Unix 系统中在执行完子进程后会立即将共享内存释放,并报出以下警告

该警告会出现多次。个人推测是该警告提醒共享内存在进程池里的进程中没有被释放,shared_memory 模块中追踪该内存块的部分报出了该警告,进程池中的内存退出时在为了防止出现内存泄漏的问题强制释放了该内存块。

个人认为该问题并不合理,共享内存本应方便进程间通信,在 A 进程中创建内存块然后, B进程获取并使用,B进程在退出时并不应该释放,C 进程还想继续使用该内存块。

解决办法

python 复制代码
from multiprocessing import Process, resource_tracker
from multiprocessing.shared_memory import SharedMemory


def remove_shm_from_resource_tracker():
    """Monkey-patch multiprocessing.resource_tracker so SharedMemory won't be tracked

    More details at: https://bugs.python.org/issue38119
    """

    def fix_register(name, rtype):
        if rtype == "shared_memory":
            return
        return resource_tracker._resource_tracker.register(self, name, rtype)
    resource_tracker.register = fix_register

    def fix_unregister(name, rtype):
        if rtype == "shared_memory":
            return
        return resource_tracker._resource_tracker.unregister(self, name, rtype)
    resource_tracker.unregister = fix_unregister

    if "shared_memory" in resource_tracker._CLEANUP_FUNCS:
        del resource_tracker._CLEANUP_FUNCS["shared_memory"]

以上函数来自于文档参考,能够通过 resource_tracker.py 解除进程对共享内存块的绑定,防止进程退出后释放共享内存块,只需在使用共享内存前调用 remove_shm_from_resource_tracker() 函数,就可以防止内存块提前被释放。

PS:该函数在使用时至少要有一个进程不调用该函数,否则会导致创建的内存块不被释放,造成内存泄漏的风险!!!!!!!!!!!!

相关推荐
tao35566718 小时前
【Python刷力扣hot100】42. Trapping Rain Water
开发语言·python·leetcode
一只安18 小时前
从零开发AI(不依赖任何模型)
人工智能·python
2501_9387820919 小时前
实战 Python NLP:处理 PDF 文档批量提取文本并进行主题建模
python·自然语言处理·pdf
成长痕迹19 小时前
【Python与Matlab数据分析对比】
python·matlab·数据分析
11年老程序猿在线搬砖19 小时前
如何搭建自己的量化交易平台
大数据·人工智能·python·自动交易·量化交易系统
错把套路当深情19 小时前
Kotlin保留小数位的三种方法
开发语言·python·kotlin
错把套路当深情19 小时前
Kotlin基础类型扩展函数使用指南
python·微信·kotlin
千里码aicood19 小时前
python+vue旅游购票管理系统设计(源码+文档+调试+基础修改+答疑)
vue.js·python·旅游
B站_计算机毕业设计之家19 小时前
python电商商品评论数据分析可视化系统 爬虫 数据采集 Flask框架 NLP情感分析 LDA主题分析 Bayes评论分类(源码) ✅
大数据·hadoop·爬虫·python·算法·数据分析·1024程序员节
写代码的安徒生19 小时前
调用 Google Veo 3.1 API 批量制作电商产品 UGC 视频
python·音视频