diff --git a/rts/Capability.c b/rts/Capability.c
index 3d55b421f8e453e5c5be0e1b55f5dd8f3a930cd5..510656f473b6c4911f54e32b12cc50cca2e87b1f 100644
--- a/rts/Capability.c
+++ b/rts/Capability.c
@@ -673,8 +673,7 @@ shutdownCapability (Capability *cap, Task *task)
 	    continue;
 	}
 	debugTrace(DEBUG_sched, "capability %d is stopped.", cap->no);
-        stgFree(cap->mut_lists);
-        freeSparkPool(&cap->r.rSparks);
+    freeCapability(cap);
 	RELEASE_LOCK(&cap->lock);
 	break;
     }
@@ -712,4 +711,11 @@ tryGrabCapability (Capability *cap, Task *task)
 
 #endif /* THREADED_RTS */
 
+void
+freeCapability (Capability *cap) {
+    stgFree(cap->mut_lists);
+#if defined(THREADED_RTS) || defined(PARALLEL_HASKELL)
+    freeSparkPool(&cap->r.rSparks);
+#endif
+}
 
diff --git a/rts/Capability.h b/rts/Capability.h
index dd17863c604c3b759ef961163dca4a6adf703e66..dedd6351b693bebc23ba0f0bac3584e29f2f17d5 100644
--- a/rts/Capability.h
+++ b/rts/Capability.h
@@ -232,6 +232,9 @@ extern void grabCapability (Capability **pCap);
 
 #endif /* !THREADED_RTS */
 
+// Free a capability on exit
+void freeCapability (Capability *cap);
+
 /* -----------------------------------------------------------------------------
  * INLINE functions... private below here
  * -------------------------------------------------------------------------- */
diff --git a/rts/ProfHeap.c b/rts/ProfHeap.c
index 4aecd0b5b3fcc6b9b92db05c4a3f290a686eba33..e93151d4f44dd930b9fd4067c33157268b3535eb 100644
--- a/rts/ProfHeap.c
+++ b/rts/ProfHeap.c
@@ -316,6 +316,13 @@ initEra(Census *census)
     census->drag_total = 0;
 }
 
+STATIC_INLINE void
+freeEra(Census *census)
+{
+    arenaFree(census->arena);
+    freeHashTable(census->hash, NULL);
+}
+
 /* --------------------------------------------------------------------------
  * Increases era by 1 and initialize census[era].
  * Reallocates gi[] and increases its size if needed.
@@ -355,6 +362,10 @@ void initProfiling1( void )
 {
 }
 
+void freeProfiling1( void )
+{
+}
+
 void initProfiling2( void )
 {
   if (RtsFlags.ProfFlags.doHeapProfile) {
@@ -493,6 +504,14 @@ endHeapProfiling(void)
     }
 #endif
 
+    {
+        nat t;
+        for (t = 0; t <= era; t++) {
+            freeEra( &censuses[t] );
+        }
+    }
+    stgFree(censuses);
+
     seconds = mut_user_time();
     printSample(rtsTrue, seconds);
     printSample(rtsFalse, seconds);
diff --git a/rts/Profiling.c b/rts/Profiling.c
index a8650788e95df0480f0f89b90fa449f323ae0f8e..4e759b6942a85ba7d618d3ebc01e89e4859a71bb 100644
--- a/rts/Profiling.c
+++ b/rts/Profiling.c
@@ -185,6 +185,12 @@ initProfiling1 (void)
    */
 }
 
+void
+freeProfiling1 (void)
+{
+    arenaFree(prof_arena);
+}
+
 void
 initProfiling2 (void)
 {
diff --git a/rts/Profiling.h b/rts/Profiling.h
index d968349a527cefe6500dd26e3341504f2ff139fb..edfc1b2c5e9851dbdefbf76f59839670affd6798 100644
--- a/rts/Profiling.h
+++ b/rts/Profiling.h
@@ -13,6 +13,7 @@
 
 #if defined(PROFILING) || defined(DEBUG)
 void initProfiling1 ( void );
+void freeProfiling1 ( void );
 void initProfiling2 ( void );
 void endProfiling   ( void );
 
diff --git a/rts/RtsSignals.h b/rts/RtsSignals.h
index eafeeaaf5543abecbcf22fc5b2dc44c0b630fec5..6d9374a70c5e6b4db6e304c6c6fe9b5630588c9d 100644
--- a/rts/RtsSignals.h
+++ b/rts/RtsSignals.h
@@ -41,6 +41,8 @@ extern void initUserSignals(void);
  */
 extern void initDefaultHandlers(void);
 
+extern void freeSignalHandlers(void);
+
 /*
  * Function: blockUserSignals()
  *
diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c
index 87df96a13c91a36d41252e863ab3b7353ed46af1..7193876970c59c87063f1ee84f48fb38236eef46 100644
--- a/rts/RtsStartup.c
+++ b/rts/RtsStartup.c
@@ -378,6 +378,10 @@ hs_exit(void)
     /* start timing the shutdown */
     stat_startExit();
     
+#if defined(RTS_USER_SIGNALS)
+    freeSignalHandlers();
+#endif
+
 #if defined(THREADED_RTS)
     ioManagerDie();
 #endif
@@ -447,6 +451,10 @@ hs_exit(void)
     /* free the stable pointer table */
     exitStablePtrTable();
 
+#if defined(PROFILING) || defined(DEBUG)
+    freeProfiling1();
+#endif
+
 #if defined(DEBUG)
     /* free the thread label table */
     freeThreadLabelTable();
diff --git a/rts/Schedule.c b/rts/Schedule.c
index 8ebedd4279f4d897e286efc7aadeeda9f0e9fd2a..a11a15e94d9733a9a84c79adddaa61e60597dc66 100644
--- a/rts/Schedule.c
+++ b/rts/Schedule.c
@@ -2581,6 +2581,8 @@ exitScheduler( void )
 	boundTaskExiting(task);
 	stopTaskManager();
     }
+#else
+    freeCapability(&MainCapability);
 #endif
 }
 
@@ -2588,6 +2590,9 @@ void
 freeScheduler( void )
 {
     freeTaskManager();
+    if (n_capabilities != 1) {
+        stgFree(capabilities);
+    }
 #if defined(THREADED_RTS)
     closeMutex(&sched_mutex);
 #endif
diff --git a/rts/posix/Signals.c b/rts/posix/Signals.c
index a5044cd6de08c34af2d904128e91b65a5e983d4f..2380eacfbdd3bf29161644792155ffa45a6626ff 100644
--- a/rts/posix/Signals.c
+++ b/rts/posix/Signals.c
@@ -545,4 +545,11 @@ initDefaultHandlers()
 #endif
 }
 
+void
+freeSignalHandlers(void) {
+    if (signal_handlers != NULL) {
+        stgFree(signal_handlers);
+    }
+}
+
 #endif /* RTS_USER_SIGNALS */
diff --git a/rts/win32/ConsoleHandler.c b/rts/win32/ConsoleHandler.c
index 5b5cfc338bcde8f70dc12684a5f3a092ab7178ce..a2de74b54a2f9d606cad7e01de65bf15bb8592e5 100644
--- a/rts/win32/ConsoleHandler.c
+++ b/rts/win32/ConsoleHandler.c
@@ -52,6 +52,11 @@ initUserSignals(void)
     return;
 }
 
+void
+freeSignalHandlers(void) {
+    /* Do nothing */
+}
+
 /* Seems to be a bit of an orphan...where used? */
 void
 finiUserSignals(void)