-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RadioButton is not currently being Garbage Collected #20023
Comments
@jsuarezruiz I was hoping someone else would take these over, and I would help? |
Posting here, @tj-devel709 and my findings. #20472 does not seem like it would fix the problem here, as there are two different underlying problems:
There may be a third leak in
(But we should retest after fixing 1 and 2 above). |
Context: dotnet#20023 (comment) One of the underlying reasons `RadioButton` appears to leak, is that it happens to use a `TapGestureRecognizer` internally. When testing, @tj-devel709 and I found we could add pretty much *any* recognizer to a simple control like `BoxView`, and it would cause the `BoxView` to live forever. I could reproduce this in a new unit test that I setup for each type of gesture recognizer. `GesturePlatformManager.iOS.cs` had two "cycles": * `*Handler` -> ... -> `GesturePlatformManager` -> `*Handler` * `*GestureRecognizer` -> `GesturePlatformManager` -> `*GestureRecognizer` To fix these, we can make `GesturePlatformManager` not have strong references pointing *back* to its parent classes: * Make `_handler` a `WeakReference<IPlatformViewHandler>` * Make `_gestureRecognizers` a `ConditionalWeakTable` With these changes the tests pass, except for `PanGestureRecognizer`, which had a "closure" in using the `panRecognizer` variable. I fixed this one with: * `((PanGestureRecognizer)panGestureRecognizer)` as `panGestureRecognizer` was backed by a `WeakReference`.
Context: https://github.com/heyThorsten/GCTest Fixes: dotnet#20023 In testing the above sample, a page with a `RadioButton` has a memory leak due to the usage of `Border.StrokeShape`. There was also a slight "rabbit" hole, where we thought there was also an issue with `GestureRecognizers`. But this was not the case in a real app (just unit tests): * dotnet#21089 It turns out that when `GestureRecognizers` are used in `MemoryTests`, they will leak if there is no `Window` involved. Instead of using `MemoryTests` like I would traditionally, we should instead use `NavigationPageTests.DoesNotLeak()`. I can reproduce the problem with `RadioButton` *and* a `Window` exists in the test. ~~ Underlying issue ~~ It appears that `Border.StrokeShape` does not use the same pattern as other properties like `Border.Stroke`: * On set: `SetInheritedBindingContext(visualElement, BindingContext);` * On unset: `SetInheritedBindingContext(visualElement, null);` It instead used: * On set: `AddLogicalChild(visualElement);` * On unset: `RemoveLogicalChild(visualElement);` 6136a8a that introduced these does not mention why one was used over another. I am unsure if this will cause a problem, but it fixes the leak.
Context: https://github.com/heyThorsten/GCTest Fixes: #20023 In testing the above sample, a page with a `RadioButton` has a memory leak due to the usage of `Border.StrokeShape`. There was also a slight "rabbit" hole, where we thought there was also an issue with `GestureRecognizers`. But this was not the case in a real app (just unit tests): * #21089 It turns out that when `GestureRecognizers` are used in `MemoryTests`, they will leak if there is no `Window` involved. Instead of using `MemoryTests` like I would traditionally, we should instead use `NavigationPageTests.DoesNotLeak()`. I can reproduce the problem with `RadioButton` *and* a `Window` exists in the test. ~~ Underlying issue ~~ It appears that `Border.StrokeShape` does not use the same pattern as other properties like `Border.Stroke`: * On set: `SetInheritedBindingContext(visualElement, BindingContext);` * On unset: `SetInheritedBindingContext(visualElement, null);` It instead used: * On set: `AddLogicalChild(visualElement);` * On unset: `RemoveLogicalChild(visualElement);` 6136a8a that introduced these does not mention why one was used over another. I am unsure if this will cause a problem, but it fixes the leak. Other changes: * `propertyChanging` seems wrong? Reading the existing code, it should be checking `oldvalue` instead of `newvalue`?
Description
Breaking out remaining work for: #18365
Add tests to ensure that RadioButton is GC'd.
Link to public reproduction project repository
https://github.com/heyThorsten/GCTest
The text was updated successfully, but these errors were encountered: