You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(android): free decoded images on the new backend - #427
On the new Android backend, every ViewModelImageProperty.set() decoded a new ImageAsset on the command server and never closed it, even when setting the same image again. Swapping images grew GPU memory from 304 MB to 4.8 GB over 211 swaps (2048×2048 PNGs, emulator). The handle is now closed right after setImage (the property keeps its own ref), and memory stays flat at ~311 MB.
set(undefined) now clears the image instead of being ignored. Sets run on a single-threaded scope so they apply in call order. Before, a clear could be overtaken by an earlier set that was still decoding.
Adds a harness test for set/clear. Memory isn't asserted automatically; use the AndroidMemoryLeak reproducer from #426 (image swap scenarios) to check.
Every image property set() decoded a new ImageAsset on the command server
and never closed it, so each swap leaked a decoded image. The handle is now
closed once the property holds its own ref. set(undefined) clears the image
instead of being ignored, and sets apply in call order.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
An Android coroutine race can restore an image after clearing, and the regression test neither waits for mutation completion nor verifies the cleared state.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The Android setter still allows a suspended image decode to overwrite a later clear, while the test neither waits for native completion nor verifies the final cleared state.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Independent sequencing state across image-property lookups allows an earlier decode to overwrite a later clear, while the harness can pass without verifying asynchronous set/clear results.
No open issues 🎉
1 previously missed issue
In code that hasn't changed since last review
Reuse image property state across repeated lookups
HybridViewModelInstance.imageProperty() creates a fresh wrapper on every lookup (HybridViewModelInstance.kt:79–81), so repeated lookups use independent generation counters and dispatchers. Calling instance.imageProperty(path).set(image) followed by instance.imageProperty(path).set(undefined) can therefore let the earlier decode finish after the clear and restore the image. Share the sequencing and generation state per underlying instance/path, or reuse the property wrapper across lookups.
Re the previously missed issue in Copilot's last review (independent sequencing per imageProperty() lookup): fixed in 9a27f55. HybridViewModelInstance now keeps one sequencer per path (a serial scope plus a generation counter), and every wrapper it returns for that path shares it.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The Android image set/clear harness can pass despite failed native writes because it neither waits for asynchronous operations nor verifies their results before disposing resources.
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
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.
On the new Android backend, every
ViewModelImageProperty.set()decoded a newImageAsseton the command server and never closed it, even when setting the same image again. Swapping images grew GPU memory from 304 MB to 4.8 GB over 211 swaps (2048×2048 PNGs, emulator). The handle is now closed right aftersetImage(the property keeps its own ref), and memory stays flat at ~311 MB.set(undefined)now clears the image instead of being ignored. Sets run on a single-threaded scope so they apply in call order. Before, a clear could be overtaken by an earlier set that was still decoding.Adds a harness test for set/clear. Memory isn't asserted automatically; use the
AndroidMemoryLeakreproducer from #426 (image swap scenarios) to check.