-
Notifications
You must be signed in to change notification settings - Fork 64
[tests] rework JavaObjectTest, use FinalizerHelper from mono/mono #899
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
Conversation
Context: dotnet/runtime#60638 (comment) Context: dotnet/android#6363 We were seeing `JavaObjectTest.Dispose_Finalized()` fail in a .NET 6 bump with `$(UseInterpreter)` set to `true`: Expected: True But was: False at Java.InteropTests.JavaObjectTest.Dispose_Finalized() at System.Reflection.RuntimeMethodInfo.Invoke(Object , BindingFlags , Binder , Object[] , CultureInfo ) The first recommendation was to use a helper method from mono/mono's unit tests: https://github.com/mono/mono/blob/8266c5604b8c03882f2b06af27fdea46b142d6b9/mono/mini/TestHelpers.cs#L12 I removed usage of all `System.Threading` in `JavaObjectTest` in favor of this helper method. This did not solve this issue; we need to fix up the test to wait for two GCs to complete: FinalizerHelpers.PerformNoPinAction (() => { FinalizerHelpers.PerformNoPinAction (() => { var v = new JavaDisposedObject (() => d = true, () => f = true); GC.KeepAlive (v); }); JniEnvironment.Runtime.ValueManager.CollectPeers (); }); JniEnvironment.Runtime.ValueManager.CollectPeers (); With this change in place, the test now passes: https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=5361266&view=ms.vss-test-web.build-test-results-tab We can also remove the category added in d1d64c1.
33419e8 to
e013608
Compare
| // be more likely to happen with the interpreter which reuses more stack. | ||
| static class FinalizerHelpers | ||
| { | ||
| private static IntPtr aptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BrzVlad: Why is this member needed at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Answer: probably to prevent optimizing out the stackalloc: https://discord.com/channels/732297728826277939/732297837953679412/902261731471007765
| var v = new JavaDisposedObject (() => d = true, () => f = true); | ||
| GC.KeepAlive (v); | ||
| }); | ||
| JniEnvironment.Runtime.ValueManager.CollectPeers (); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change somewhat confuses me: we need to call GC.Collect() from both a new thread and the main thread in order to get the test to pass? Instead of invoking GC.Collect() from the main thread twice?
This is very confusing to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I understood a single call to FinalizerHelpers.PerformNoPinAction() ensures one GC.
And so we need two GCs for the finalizer to always run in this case. @BrzVlad is that correct?
Details here: dotnet/runtime#60638 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that, if an object is alive then the GC will scan it and, by doing so, it will probably store it in the stack somewhere. In very unfortunate scenarios, at the second collection, the pinning step will find this reference existing on the stack and will pin the object (that might have now been dead otherwise). Because the JavaDisposedObject is alive during the first collection, we do this collection on a separate thread, so the second GC doesn't get to find this left over references on the stack.
|
work-in-progress commit message: Context: https://github.com/xamarin/xamarin-android/pull/6363
Context: https://github.com/dotnet/runtime/issues/60638#issuecomment-949849104
Context: d1d64c10281eaa895fa415dfcafb8ed716a0db3c
Context: https://github.com/xamarin/xamarin-android/commit/c2c9ed47c94a03801986233ec9db860f0ef1daca
We were seeing `JavaObjectTest.Dispose_Finalized()` fail in a .NET 6
bump in xamarin-android with `$(UseInterpreter)` set to `true`:
Expected: True
But was: False
at Java.InteropTests.JavaObjectTest.Dispose_Finalized()
at System.Reflection.RuntimeMethodInfo.Invoke(Object , BindingFlags , Binder , Object[] , CultureInfo )
The first recommendation was to use a helper method from mono/mono's
unit tests:
* https://github.com/mono/mono/blob/8266c5604b8c03882f2b06af27fdea46b142d6b9/mono/mini/TestHelpers.cs#L12
I removed usage of all `System.Threading` in `JavaObjectTest` in
favor of this helper method.
This did not solve this issue; we need to fix up the test to wait for
two GCs to complete:
FinalizerHelpers.PerformNoPinAction (() => {
FinalizerHelpers.PerformNoPinAction (() => {
var v = new JavaDisposedObject (() => d = true, () => f = true);
GC.KeepAlive (v);
});
JniEnvironment.Runtime.ValueManager.CollectPeers ();
});
JniEnvironment.Runtime.ValueManager.CollectPeers ();
With this change in place, the test now passes:
* https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=5361266&view=ms.vss-test-web.build-test-results-tab
We can also remove the category added in d1d64c10. |
Context: dotnet/runtime#60638 (comment)
Context: dotnet/android#6363
We were seeing
JavaObjectTest.Dispose_Finalized()fail in a .NET 6bump with
$(UseInterpreter)set totrue:The first recommendation was to use a helper method from mono/mono's
unit tests:
https://github.com/mono/mono/blob/8266c5604b8c03882f2b06af27fdea46b142d6b9/mono/mini/TestHelpers.cs#L12
I removed usage of all
System.ThreadinginJavaObjectTestin favorof this helper method.
This did not solve this issue; we need to fix up the test to wait for
two GCs to complete:
With this change in place, the test now passes:
https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=5361266&view=ms.vss-test-web.build-test-results-tab
We can also remove the category added in d1d64c1.