-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
ThreadGroup instance leaked when using Timeout rule #1517
Conversation
@kcooney Can you please take a look? IIRC you're most familiar with this part of the codebase. |
fail("A 'FailOnTimeoutGroup' thread group remains referenced after the test execution."); | ||
} | ||
} | ||
} |
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 readability of the test can be improved by extracting a method subGroupsOfCurrentThread
@Test
public void threadGroupNotLeaked()
throws Throwable {
Collection<ThreadGroup> groupsBeforeSet = subGroupsOfCurrentThread();
evaluateWithWaitDuration(0);
for (ThreadGroup group: subGroupsOfCurrentThread()) {
if(!groupsBeforeSet.contains(group) && "FailOnTimeoutGroup".equals(group.getName())) {
fail("A 'FailOnTimeoutGroup' thread group remains referenced after the test execution.");
}
}
}
private Collection<ThreadGroup> subGroupsOfCurrentThread() {
ThreadGroup[] subGroups = new ThreadGroup[256];
int numGroups = currentThread().getThreadGroup().enumerate(subGroups);
return asList(subGroups).subList(0, numGroups);
}
Thanks for extracting the method |
throw throwable; | ||
} | ||
} finally { | ||
thread.join(100); |
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.
Any reason why we can't pass 1 to thread.join()
? At this point, the test either completed (in which case this should return right away) or the test timed out (in which case the thread will likely take more than 100ms to exit). Waiting extra time just makes the test run longer.
In fact, maybe we shouldn't call join at all. thread.join() can throw InterruptedException
.
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 reduced the timeout as suggested.
join
has to be called because otherwise the thread will still be active when calling threadGroup.destroy();
, which will throw an IllegalThreadStateException
and keep the group referenced, causing the leak.
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.
Thanks for the fix!
@elrodro83 Note I applied a minor code change to your branch, so you'll need to pull it back to your local repo before making more changes. |
* Handle thread interruption
@kcooney pushed the requested change. |
@elrodro83 Could you please update the release notes in the wiki to document this change? Thanks! |
Added entry in release notes, in the |
Thank you for the review and merge! @kcooney @stefanbirkner |
@kcooney since this change caused regressions for tests of HBase and EclEmma and now also at least one Jenkins plugin, perhaps it should be either reverted, or made opt-in (e.g. |
My experience with the In Eclipse Californium it causes unit tests to fail randomly . In my opinion, if such a feature is required, please
As temporary workaround I try to ensure, that all "static" thread-groups are initialized before any Timeout rule. |
FYI: I'm proposing we undo this change and instead mark the thread group as a daemon group; see #1687 |
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.
gg
This was seen with heavy impact because Spring uses the ThreadGroupContext to store internal information.
The thread group created for handling the timeout of tests is never destroy, so the
main
thread group keeps a reference to all timeout groups created during the tests. This causes the threadGroup to remain in memory, and all of its context along with it.This change avoids that by destroying the ThreadGroup after the test.
However, in some cases (like if a thread from the group is hanged), the ThreadGroup destruction fails. In that case, the exception is ignored so the behavior is not changed.