提交 c9e7b88e 编写于 作者: I igerasim

8022321: java/lang/ref/OOMEInReferenceHandler.java fails intermittently

Summary: preload/preinitialize InterruptedException and Cleaner classes and catch OOME from instanceof operator in ReferenceHandler
Reviewed-by: dholmes, mchung, srikchan
上级 f436e0fc
...@@ -111,7 +111,7 @@ public abstract class Reference<T> { ...@@ -111,7 +111,7 @@ public abstract class Reference<T> {
* therefore critical that any code holding this lock complete as quickly * therefore critical that any code holding this lock complete as quickly
* as possible, allocate no new objects, and avoid calling user code. * as possible, allocate no new objects, and avoid calling user code.
*/ */
static private class Lock { }; static private class Lock { }
private static Lock lock = new Lock(); private static Lock lock = new Lock();
...@@ -126,6 +126,22 @@ public abstract class Reference<T> { ...@@ -126,6 +126,22 @@ public abstract class Reference<T> {
*/ */
private static class ReferenceHandler extends Thread { private static class ReferenceHandler extends Thread {
private static void ensureClassInitialized(Class<?> clazz) {
try {
Class.forName(clazz.getName(), true, clazz.getClassLoader());
} catch (ClassNotFoundException e) {
throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
}
}
static {
// pre-load and initialize InterruptedException and Cleaner classes
// so that we don't get into trouble later in the run loop if there's
// memory shortage while loading/initializing them lazily.
ensureClassInitialized(InterruptedException.class);
ensureClassInitialized(Cleaner.class);
}
ReferenceHandler(ThreadGroup g, String name) { ReferenceHandler(ThreadGroup g, String name) {
super(g, name); super(g, name);
} }
...@@ -133,37 +149,40 @@ public abstract class Reference<T> { ...@@ -133,37 +149,40 @@ public abstract class Reference<T> {
public void run() { public void run() {
for (;;) { for (;;) {
Reference<Object> r; Reference<Object> r;
synchronized (lock) { Cleaner c;
if (pending != null) { try {
r = pending; synchronized (lock) {
pending = r.discovered; if (pending != null) {
r.discovered = null; r = pending;
} else { // 'instanceof' might throw OutOfMemoryError sometimes
// The waiting on the lock may cause an OOME because it may try to allocate // so do this before un-linking 'r' from the 'pending' chain...
// exception objects, so also catch OOME here to avoid silent exit of the c = r instanceof Cleaner ? (Cleaner) r : null;
// reference handler thread. // unlink 'r' from 'pending' chain
// pending = r.discovered;
// Explicitly define the order of the two exceptions we catch here r.discovered = null;
// when waiting for the lock. } else {
// // The waiting on the lock may cause an OutOfMemoryError
// We do not want to try to potentially load the InterruptedException class // because it may try to allocate exception objects.
// (which would be done if this was its first use, and InterruptedException lock.wait();
// were checked first) in this situation. continue;
// }
// This may lead to the VM not ever trying to load the InterruptedException
// class again.
try {
try {
lock.wait();
} catch (OutOfMemoryError x) { }
} catch (InterruptedException x) { }
continue;
} }
} catch (OutOfMemoryError x) {
// Give other threads CPU time so they hopefully drop some live references
// and GC reclaims some space.
// Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
// persistently throws OOME for some time...
Thread.yield();
// retry
continue;
} catch (InterruptedException x) {
// retry
continue;
} }
// Fast path for cleaners // Fast path for cleaners
if (r instanceof Cleaner) { if (c != null) {
((Cleaner)r).clean(); c.clean();
continue; continue;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册