Repository navigation
fix: off-main-thread null check in ReleaseMemoryTexture/ReleaseMemorySprite - #46
Open
niclas-bolle wants to merge 1 commit into
Open
niclas-bolle wants to merge 1 commit into
niclas-bolle wants to merge 1 commit into
Conversation
…Sprite When a Reference is finalized without Dispose(), its finalizer clears the memory cache from the GC finalizer thread. The off-main-thread branch of ReleaseMemoryTexture / ReleaseMemorySprite called IsNull(), whose Unity == throws "EnsureRunningOnMainThread can only be called from the main thread". The cache entry was already removed, so the texture was never destroyed. Use ReferenceEquals for the off-thread pre-check; the UniTask.Post callback still does the full IsNull() check on the main thread. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When a
Reference<Texture2D>is garbage-collected withoutDispose(),~Reference()runsDispose()→ImageLoader.ClearMemoryCache(url)on the GC finalizer thread. This throws:ReleaseMemoryTexturealready handles the off-main-thread case by postingDestroyImmediateto the main thread viaUniTask.Post. But the pre-check right before the post callsIsNull(), which uses Unity's overloaded==and throws off the main thread.Safe.Runcatches the exception. By thenClearMemoryCachehas already removed the entry from the memory cache, so the texture is never destroyed and leaks.ReleaseMemorySpritehas the same pre-check.Fix
In the off-main-thread branch only, the pre-check now uses
ReferenceEquals(obj, null). TheUniTask.Postcallback still runs the fullIsNull()check on the main thread before destroying. The main-thread branch is unchanged.Testing
We run this patch in a production Unity 6 (6000.3) project. Before it, the exception above showed up regularly in the Editor during Play Mode whenever a GC finalized a leaked
Reference.With the patch applied, I checked it deterministically: I created a
Referencefor a cached texture, dropped it withoutDispose(), and forcedGC.Collect(); GC.WaitForPendingFinalizers();. There was no exception. Right after the GC the cache entry was gone but the texture was still alive, which shows the destroy was posted from the finalizer thread. The texture was destroyed on the next main-thread frame.