mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
avoid running out of OS resources due to zombie thread accumulation
The bug here is that when a thread exits and becomes a "zombie", the OS resources associated with it are not necessarily released until we actually join and dispose of that thread. Since that only happens during garbage collection, and collection normally only happens in response to heap memory pressure, there's no guarantee that we'll GC frequently enough to clean up zombies promptly and avoid running out of resources. The solution is to force a GC whenever we start a new thread and there are at least N zombies waiting to be disposed, where N=16 for now.
This commit is contained in:
parent
b45528203d
commit
c3256c2874
@ -3231,12 +3231,20 @@ EXPORT(JVM_DisableCompiler)(Thread*, jclass)
|
||||
// ignore
|
||||
}
|
||||
|
||||
uint64_t
|
||||
jvmStartThread(Thread* t, uintptr_t* arguments)
|
||||
{
|
||||
jobject thread = reinterpret_cast<jobject>(arguments[0]);
|
||||
|
||||
return startThread(t, *thread) != 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
EXPORT(JVM_StartThread)(Thread* t, jobject thread)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(thread) };
|
||||
|
||||
startThread(t, *thread);
|
||||
run(t, jvmStartThread, arguments);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
|
@ -229,6 +229,9 @@ turnOffTheLights(Thread* t)
|
||||
visitAll(t, t->m->rootThread, disposeNoRemove);
|
||||
|
||||
System* s = m->system;
|
||||
|
||||
expect(s, m->threadCount == 0);
|
||||
|
||||
Heap* h = m->heap;
|
||||
Processor* p = m->processor;
|
||||
Classpath* c = m->classpath;
|
||||
@ -2435,6 +2438,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder,
|
||||
propertyCount(propertyCount),
|
||||
arguments(arguments),
|
||||
argumentCount(argumentCount),
|
||||
threadCount(0),
|
||||
activeCount(0),
|
||||
liveCount(0),
|
||||
daemonCount(0),
|
||||
@ -2653,6 +2657,8 @@ Thread::dispose()
|
||||
}
|
||||
}
|
||||
|
||||
-- m->threadCount;
|
||||
|
||||
m->heap->free(defaultHeap, ThreadHeapSizeInBytes);
|
||||
|
||||
m->processor->dispose(this);
|
||||
@ -2864,6 +2870,7 @@ enter(Thread* t, Thread::State s)
|
||||
INCREMENT(&(t->m->activeCount), 1);
|
||||
if (t->state == Thread::NoState) {
|
||||
++ t->m->liveCount;
|
||||
++ t->m->threadCount;
|
||||
}
|
||||
t->state = s;
|
||||
} break;
|
||||
|
@ -120,6 +120,10 @@ const unsigned ThreadHeapPoolSize = 64;
|
||||
const unsigned FixedFootprintThresholdInBytes
|
||||
= ThreadHeapPoolSize * ThreadHeapSizeInBytes;
|
||||
|
||||
// number of zombie threads which may accumulate before we force a GC
|
||||
// to clean them up:
|
||||
const unsigned ZombieCollectionThreshold = 16;
|
||||
|
||||
enum FieldCode {
|
||||
VoidField,
|
||||
ByteField,
|
||||
@ -1299,6 +1303,7 @@ class Machine {
|
||||
unsigned propertyCount;
|
||||
const char** arguments;
|
||||
unsigned argumentCount;
|
||||
unsigned threadCount;
|
||||
unsigned activeCount;
|
||||
unsigned liveCount;
|
||||
unsigned daemonCount;
|
||||
@ -1994,6 +1999,7 @@ addThread(Thread* t, Thread* p)
|
||||
assert(t, p->state == Thread::NoState);
|
||||
|
||||
p->state = Thread::IdleState;
|
||||
++ t->m->threadCount;
|
||||
++ t->m->liveCount;
|
||||
|
||||
p->peer = p->parent->child;
|
||||
@ -2012,6 +2018,7 @@ removeThread(Thread* t, Thread* p)
|
||||
assert(t, p->state == Thread::IdleState);
|
||||
|
||||
-- t->m->liveCount;
|
||||
-- t->m->threadCount;
|
||||
|
||||
t->m->stateLock->notifyAll(t->systemThread);
|
||||
|
||||
@ -2020,11 +2027,25 @@ removeThread(Thread* t, Thread* p)
|
||||
if (p->javaThread) {
|
||||
threadPeer(t, p->javaThread) = 0;
|
||||
}
|
||||
|
||||
p->dispose();
|
||||
}
|
||||
|
||||
inline Thread*
|
||||
startThread(Thread* t, object javaThread)
|
||||
{
|
||||
{ PROTECT(t, javaThread);
|
||||
|
||||
stress(t);
|
||||
|
||||
ACQUIRE_RAW(t, t->m->stateLock);
|
||||
|
||||
if (t->m->threadCount > t->m->liveCount + ZombieCollectionThreshold) {
|
||||
fprintf(stderr, "hit zombie collection threshold\n");
|
||||
collect(t, Heap::MinorCollection);
|
||||
}
|
||||
}
|
||||
|
||||
Thread* p = t->m->processor->makeThread(t->m, javaThread, t);
|
||||
|
||||
addThread(t, p);
|
||||
|
Loading…
Reference in New Issue
Block a user