Skip to content

Commit edf7866

Browse files
authored
Atlas: Fix memory leak from self reference (#2678)
1 parent a17e955 commit edf7866

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

arcade/texture_atlas/atlas_default.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
TYPE_CHECKING,
1111
Sequence,
1212
)
13-
from weakref import WeakSet, WeakValueDictionary, finalize
13+
from weakref import WeakSet, WeakValueDictionary, finalize, ref
1414

1515
import PIL.Image
1616
from PIL import Image, ImageDraw
@@ -356,14 +356,25 @@ def _add_texture_ref(self, texture: Texture, create_finalizer=True) -> None:
356356
self._image_ref_count.inc_ref(texture.image_data)
357357

358358
if create_finalizer:
359-
ref = finalize(
359+
atlas_ref = ref(self)
360+
361+
# NOTE: The finalizer needs to be completely decoupled from the atlas
362+
# or it will self-reference and not die unless all the textures in it
363+
# are removed. This lead to leaking orphaned atlases when you have
364+
# pre-loaded shared textures in multiple atlases.
365+
def finalizer_callback(atlas_name, hash):
366+
atlas = atlas_ref()
367+
if atlas is not None:
368+
atlas._remove_texture_by_identifiers(atlas_name, hash)
369+
370+
finalizer_ref = finalize(
360371
texture,
361-
self._remove_texture_by_identifiers,
372+
finalizer_callback,
362373
texture.atlas_name,
363374
texture.image_data.hash,
364375
)
365376
# Don't bother removing texture on program exit
366-
ref.atexit = False
377+
finalizer_ref.atexit = False
367378
self._finalizers_created += 1
368379

369380
self._textures_added += 1

0 commit comments

Comments
 (0)