-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8300727: java/awt/List/ListGarbageCollectionTest/AwtListGarbageCollectionTest.java failed with "List wasn't garbage collected" #12594
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
…tionTest.java failed with "List wasn't garbage collected"
|
👋 Welcome back aivanov! A progress list of the required criteria for merging this PR into |
|
@aivanov-jdk The following label will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command. |
Webrevs
|
| Reference<? extends List> ref; | ||
| do { | ||
| System.out.println("Attempt " + count); | ||
| System.gc(); |
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.
As far as I remember the call of System.gc() could be ignored, and the only way to trigger GC is to trigger the OOM. Probably we can combine referenceQueue.remove(ENQUEUE_TIMEOUT) + OOM?
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.
For this reason, GC logs are enabled. If, for whatever reason, the call to System.gc() is ignored, we'll see it in the test log. Then a specific GC could be selected, for example, or another fix implemented.
OOME does not guarantee a full GC cycle either.
Having the above in mind, I'd rather keep it simple.
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.
For this reason, GC logs are enabled. If, for whatever reason, the call to System.gc() is ignored, we'll see it in the test log. Then a specific GC could be selected, for example, or another fix implemented.
As of now this test can be executed with different GC, and some of them can skip System.gc().
OOME does not guarantee a full GC cycle either.
But it guarantee that at least some GC will be always run, unlike System.gc().
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.
I followed the piece of advice in the JBS comment.
If using System.gc() is good enough for testing references:
jdk/test/jdk/java/lang/ref/ReferenceEnqueue.java
Lines 54 to 60 in f612dcf
| boolean enqueued = false; | |
| System.gc(); | |
| for (int i = 0; i < iterations; i++) { | |
| System.gc(); | |
| enqueued = (queue.remove(100) == ref); | |
| if (enqueued) break; | |
| } |
jdk/test/jdk/java/lang/ref/PhantomReferentClearing.java
Lines 85 to 92 in f612dcf
| // Delete root -> O1, collect, verify P1 notified, P2 not notified. | |
| O1 = null; | |
| System.gc(); | |
| if (Q1.remove(ENQUEUE_TIMEOUT) == null) { | |
| throw new RuntimeException("P1 not notified by O1 deletion"); | |
| } else if (Q2.remove(ENQUEUE_TIMEOUT) != null) { | |
| throw new RuntimeException("P2 notified by O1 deletion."); | |
| } |
Then it should be good enough for this test too.
Perhaps, the same effect could be achieved by causing OOME in a loop. However, using System.gc() makes the intention clearer: run GC, wait for the phantom reference to be cleared and enqueued.
I can explicitly select a GC: -XX:+UseG1GC (default) or -XX:+UseSerialGC.
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.
There are lots of tests that rely on System.gc() actually triggering a gc.
SFAIK all collectors we have today will obey it unless you use
-XX:+DisableExplicitGC
If you can make the test work with that then that would be interesting but calling just System.gc() is no worse than all those other tests.
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.
Many client tests generate OOM for that, we have a special Util, see the usage of Util.generateOOME() or various implementation of generateOOME.
If the OOM + sleep(to give the GC a chance to clean the weakrefs in case of slow systems) does not work, then could it be considerred as a GC bug?
OutOfMemoryError: The Java Virtual Machine implementation has run out of either virtual or physical memory, and the automatic storage manager was unable to reclaim enough memory to satisfy an object creation request.
https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-6.html#jvms-6.3
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.
Yes, I saw this method, and it periodically calls System.gc().
I still don't understand your concern. How is generating OutOfMemoryError better than calling System.gc()?
Calling System.gc() conveys the intent in a clearer way. No OOME is required.
It generates OOM to make sure that gc will be called, unlike System.gc() which per the spec can be ignored.
That method uses both, which I suggested doing at the start. It is better to follow one approach than implement different patterns here and there. |
Can be but it's not ignored, it's respected. I provided you at least two tests which solely rely on
You didn't suggest, at least explicitly, using Nevertheless, I think generating OOME is redundant, it adds another level of complexity and makes the test slower. The flag
Perhaps, the time has come to change the approach: ditch generating OOME and just use If the developers write tests to verify |
It could be ignored per the specification.
If it is redundant then let's update all other tests which generate OOM right now and prove it. it would be better than having different approaches here and there. |
Yet it's not.
I would absolutely explore this route and would be happy to update other tests but this is out of scope for this issue. The |
|
I'm OK with the fix. This one test doesn't make things markedly worse, so let's approve it and you can start a discussion on |
|
@aivanov-jdk This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be: You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 310 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
TejeshR13
left a 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.
Looks good to me.
It is up to you, but I disagree. There was an agreement in the team to use one approach to trigger the gc, that approach was used in most of our tests, and was used in this test as well.
I agree that it is out of the scope of this issue, which actually fixed by adding the "retry" step to the test. The bug is unrelated to the replacing of OOM by the System.gc(). When why did you change it? |
Do you agree that using only If So far, your argument is that this test is now different from other tests which employ both
I already answered this question several times. I followed the piece of advice in the JBS comment: “This is not the way to provoke a full GC in a test reliably. Just use System.gc(). See e.g. That's what I did. Using I had a handful of attempts which still failed. |
I prefer to use OOM just based on the text of the specification I referred above. As per the spec, both should trigger some cleanup, but System.gc could be ignored. If we would like to change that approach then let's add a retry to this test first. Maybe the test will continue to fail if we will add just a retry. Isn't it suspicious that it started to fail now? and then replace the usage/implementation of generateOOM method by system.gc() everywhere.
But why we did not ask why "This is not the way to provoke a full GC in a test reliably"? It does not work as specified? |
|
Eventually, core-libs have their own helper method in I asked a question on core-libs-dev and hotspot-gc-dev. Two approaches were suggested: Stuart Marks provided a detailed reply with a couple of points:
Thomas also advises against using OOME:
The latest revision uses a standard helper |
mrserb
left a 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 usage of ForceGC looks fine.
|
/integrate |
|
Going to push as commit f835aaa.
Your commit was automatically rebased without conflicts. |
|
@aivanov-jdk Pushed as commit f835aaa. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
The test has become unstable recently, there were quite a few failures, on Windows mostly. I was lucky enough to find a host where the test failed consistently.
I call
System.gc()directly as suggested in comments to the bug. I usedPhantomReferenceinstead ofWeakReference.Now the test calls
System.gc()in a loop and waits for the reference to be enqueued. In majority of cases, the test exits the loop at the second attempt.Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk pull/12594/head:pull/12594$ git checkout pull/12594Update a local copy of the PR:
$ git checkout pull/12594$ git pull https://git.openjdk.org/jdk pull/12594/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 12594View PR using the GUI difftool:
$ git pr show -t 12594Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/12594.diff