[rvm-research] Memory Leaks in Thread Creation/Deletion
Carl Ritson <[email protected]>
| Newsgroups | gmane.comp.java.jikes.rvm.devel |
|---|---|
| Message-ID | <CAKDym5Np4fSBf-b7Vtv6-6WcwCAxChN1NtUNJZ4sp_xbVtWwaw@mail.gmail.com> |
Hi, For debugging I recently wrote a test that endless creates and terminates threads (attached as ThreadTest3.java). This test consistently crashes JikesRVM after about 450,000 threads have been created. The crash occurs when pthread_create fails due to a lack of resources, or as it turns out, a lack of memory. Digging around in sys.C it seems some allocation is done with C++ primitives (new/delete) and the rest with malloc/free. There doesn't appear to be an obvious reason for this. There also seem to be two distinct memory leaks: 1. the memory allocated for the parameters passed to the new thread via pthread_create is not freed. 2. the signal handling stack can be allocated twice, once by sysThreadStartup and once by sysSetupHardwareTrapHandler; however, only the stack allocated by sysThreadStartup will be release when a thread terminates. Attached is a patch which attempts to address these issues with (mostly) minimal changes: A. uses of new/delete are replaced with malloc/free. B. all calls to malloc/free pass via (existing) checking functions to check for address space overlaps. C. thread parameters are releases at thread termination. D. thread termination checks for the presence of an alternate signal stack and release it if present. For (2)/(D) I suspect that the signal stack should only be allocated once by sysThreadStartup and not by sysSetupHardwareTrapHandler. However I haven't fully investigated what the separation of concerns between these methods should be. With these changes memory leakage appears to have stopped for the test code. Kind regards, Carl ------------------------------------------------------------------------------ Slashdot TV. Video for Nerds. Stuff that matters. http://tv.slashdot.org/ _______________________________________________ Jikesrvm-researchers mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/jikesrvm-researchers
ThreadTest3.java
(application/octet-stream, 1.2 KB) - not displayed
sys-c-memory-leaks-20140905b.patch
(application/octet-stream, 3.6 KB)
diff -r 05dd10867319 tools/bootImageRunner/sys.C
--- a/tools/bootImageRunner/sys.C Thu Sep 04 17:44:40 2014 +0200
+++ b/tools/bootImageRunner/sys.C Fri Sep 05 15:13:27 2014 +0100
@@ -145,6 +145,9 @@
extern "C" void sysMonitorWait(Word);
extern "C" void sysMonitorBroadcast(Word);
+static void* checkMalloc(int);
+static void checkFree(void*);
+
// #define DEBUG_SYS
// #define DEBUG_THREAD
@@ -978,7 +981,7 @@
// create arguments
//
- sysThreadArguments = new Address[3];
+ sysThreadArguments = (Address*) checkMalloc(sizeof(Address) * 3);
sysThreadArguments[0] = tr;
sysThreadArguments[1] = ip;
sysThreadArguments[2] = fp;
@@ -1086,7 +1089,7 @@
char *stackBuf;
memset (&stack, 0, sizeof stack);
- stack.ss_sp = stackBuf = new char[SIGSTKSZ];
+ stack.ss_sp = stackBuf = (char*) checkMalloc(sizeof(char) * SIGSTKSZ);
stack.ss_flags = 0;
stack.ss_size = SIGSTKSZ;
if (sigaltstack (&stack, 0)) {
@@ -1096,18 +1099,30 @@
Address tr = ((Address *)args)[0];
- jmp_buf *jb = (jmp_buf*)malloc(sizeof(jmp_buf));
+ jmp_buf *jb = (jmp_buf*)checkMalloc(sizeof(jmp_buf));
if (setjmp(*jb)) {
- // this is where we come to terminate the thread
+ // this is where we come to terminate the thread
#ifdef RVM_FOR_HARMONY
hythread_detach(NULL);
#endif
- free(jb);
- *(int*)(tr + RVMThread_execStatus_offset) = RVMThread_TERMINATED;
-
- stack.ss_flags = SS_DISABLE;
- sigaltstack(&stack, 0);
- delete[] stackBuf;
+ checkFree(jb);
+ *(int*)(tr + RVMThread_execStatus_offset) = RVMThread_TERMINATED;
+
+ // disable the signal stack (first retreiving the current one)
+ sigaltstack(0, &stack);
+ stack.ss_flags = SS_DISABLE;
+ sigaltstack(&stack, 0);
+
+ // check if the signal stack is the one in stackBuf
+ if (stack.ss_sp != stackBuf) {
+ // no; release it as well
+ checkFree(stack.ss_sp);
+ }
+
+ // release signal stack allocated here
+ checkFree(stackBuf);
+ // release arguments
+ checkFree(args);
} else {
setThreadLocal(TerminateJmpBufKey, (void*)jb);
@@ -1198,7 +1213,7 @@
stack_t stack;
memset (&stack, 0, sizeof stack);
- stack.ss_sp = new char[SIGSTKSZ];
+ stack.ss_sp = (char*) checkMalloc(sizeof(char) * SIGSTKSZ);
stack.ss_size = SIGSTKSZ;
if (sigaltstack (&stack, 0)) {
@@ -1373,7 +1388,7 @@
hythread_monitor_t monitor;
hythread_monitor_init_with_name(&monitor, 0, NULL);
#else
- vmmonitor_t *monitor = new vmmonitor_t;
+ vmmonitor_t *monitor = (vmmonitor_t*) checkMalloc(sizeof(vmmonitor_t));
pthread_mutex_init(&monitor->mutex, NULL);
pthread_cond_init(&monitor->cond, NULL);
#endif
@@ -1389,7 +1404,7 @@
vmmonitor_t *monitor = (vmmonitor_t*)_monitor;
pthread_mutex_destroy(&monitor->mutex);
pthread_cond_destroy(&monitor->cond);
- delete monitor;
+ checkFree(monitor);
#endif
}
@@ -1688,10 +1703,8 @@
int inRVMAddressSpace(Address a);
-// Allocate memory.
-//
-extern "C" void *
-sysMalloc(int length)
+static void*
+checkMalloc(int length)
{
void *result=malloc(length);
if (inRVMAddressSpace((Address)result)) {
@@ -1700,6 +1713,20 @@
return result;
}
+static void
+checkFree(void* mem)
+{
+ free(mem);
+}
+
+// Allocate memory.
+//
+extern "C" void *
+sysMalloc(int length)
+{
+ return checkMalloc(length);
+}
+
extern "C" void *
sysCalloc(int length)
{
@@ -1711,7 +1738,7 @@
extern "C" void
sysFree(void *location)
{
- free(location);
+ checkFree(location);
}
// Zero a range of memory with non-temporal instructions on x86