2022년 10월 28일 작성
multiprocessing.shared_memory
모듈의 SharedMemory
를 사용하는 경우,SharedMemory를 사용하던 프로세스가 종료되었을 때, 연결된 공유 메모리 블록까지 릴리즈되어 다른 프로세스에서 사용이 불가능한 문제 발생한다.
(파이썬 프로세스 , , 가 같은 공유 메모리 블록에 접근하려는 상황)
가 해당 공유 메모리 블록에 접근하고, 작업을 처리한 후 프로세스 종료
Warning 발생
UserWarning: resource_tracker: There appear to be 1 leaked shared_memory objects to clean up at shutdown
warnings.warn('resource_tracker: There appear to be %d '
가 해당 공유 메모리 블록에 접근 시도
에러 발생
FileNotFoundError: [Errno 2] No such file or directory: '/test'
from multiprocessing.shared_memory import SharedMemory
### Process 1
shm = SharedMemory(name='test', create=True, size=4096)
# 대기
### Process 2
shm = SharedMemory(name='test', create=False)
# ...
exit()
# Warning 발생
### Process 3
shm = SharedMemory(name='test', create=False)
# 에러 발생
multiprocessing
라이브러리에는 ResourceTracker
가 존재하며, SharedMemory 오브젝트 생성 시 해당 오브젝트는 ResourceTracker의 감시 대상에 등록된다. (create=True인 경우나 False인 경우 모두 포함) [1]
### Lib/multiprocessing/shared_memory.py
class SharedMemory:
# ...
def __init__(self, name=None, create=False, size=0):
# ...
if _USE_POSIX:
# POSIX Shared Memory
if name is None:
while True:
name = _make_filename()
try:
self._fd = _posixshmem.shm_open(
name,
self._flags,
mode=self._mode
)
except FileExistsError:
continue
self._name = name
break
else:
name = "/" + name if self._prepend_leading_slash else name
self._fd = _posixshmem.shm_open(
name,
self._flags,
mode=self._mode
)
self._name = name
try:
if create and size:
os.ftruncate(self._fd, size)
stats = os.fstat(self._fd)
size = stats.st_size
self._mmap = mmap.mmap(self._fd, size)
except OSError:
self.unlink()
raise
resource_tracker.register(self._name, "shared_memory")
ResourceTracker는 파이썬 프로세스 종료 시 unlink 되지 않은 SharedMemory 오브젝트가 있다면 경고를 날리며 unlink를 호출한다. [2] (leak으로 간주)
### Lib/multiprocessing/resource_tracker.py
# Line 49-51
_CLEANUP_FUNCS.update({
'shared_memory': _posixshmem.shm_unlink,
})
# Line 229-239
for name in rtype_cache:
# For some reason the process which created and registered this
# resource has failed to unregister it. Presumably it has
# died. We therefore unlink it.
try:
try:
_CLEANUP_FUNCS[rtype](name)
except Exception as e:
warnings.warn('resource_tracker: %r: %s' % (name, e))
finally:
pass
파이썬 이슈트래커에 이번 버그에 대해 논의가 있었고 솔루션도 제시되어 PR이 있지만, 2022.10.28기준 3.11 버전에서도 아직 머지되지 않았으며 방치된 상태이다.
# Lib/multiprocessing/shared_memory.py
# Line 120
resource_tracker.register(self._name, "shared_memory")
# Lib/multiprocessing/shared_memory.py
# Line 120
if create:
resource_tracker.register(self._name, "shared_memory")
[1] Lib/multiprocessing/shared_memory.py - Line 120 [2] Lib/multiprocessing/resource_tracker.py