  
      guard.broadcast();
    }
-@@ -210,21 +249,40 @@ void ApplicationV8::exitContext (V8Context* context) {
+@@ -253,25 +292,112 @@ void ApplicationV8::exitContext (V8Context* context) {
+ }
+ 
+ ////////////////////////////////////////////////////////////////////////////////
++/// @brief determine which of the free contexts should be picked for the GC
++////////////////////////////////////////////////////////////////////////////////
++
++ApplicationV8::V8Context* ApplicationV8::pickContextForGc () {
++  size_t n = _freeContexts.size();
++
++  if (n == 0) {
++    // this is easy...
++    return 0;
++  }
++
++  V8GcThread* gc = dynamic_cast<V8GcThread*>(_gcThread);
++  V8Context* context = 0;
++
++  // we got more than 1 context to clean up, pick the one with the "oldest" GC stamp
++  size_t pickedContextNr = 0; // index of context with lowest GC stamp
++  
++  for (size_t i = 0; i < n; ++i) {
++    // compare last GC stamp
++    if (_freeContexts[i]->_lastGcStamp <= _freeContexts[pickedContextNr]->_lastGcStamp) {
++      pickedContextNr = i;
++    }
++  }
++  // we now have the context to clean up in pickedContextNr
++    
++  // this is the context to clean up
++  context = _freeContexts[pickedContextNr];
++  assert(context != 0);
++  
++  // now compare its last GC timestamp with the last global GC stamp
++  if (context->_lastGcStamp + _gcFrequency >= gc->getLastGcStamp()) {
++    // no need yet to clean up the context
++    return 0;
++  }
++
++  // we'll pop the context from the vector. the context might be at any position in the vector
++  // so we need to move the other elements around
++  if (n > 1) {
++    for (size_t i = pickedContextNr; i < n - 1; ++i) {
++      _freeContexts[i] = _freeContexts[i + 1];
++    }
++  }
++  _freeContexts.pop_back();
++
++  return context;
++}
++
++////////////////////////////////////////////////////////////////////////////////
+ /// @brief runs the garbage collection
  ////////////////////////////////////////////////////////////////////////////////
  
  void ApplicationV8::collectGarbage () {
 +  V8GcThread* gc = dynamic_cast<V8GcThread*>(_gcThread);
 +  assert(gc != 0);
-+  uint64_t waitTime = (uint64_t) (_gcFrequency * 1000.0 * 1000.0);
++  
++  // this flag will be set to true if we timed out waiting for a GC signal
++  // if set to true, the next cycle will use a reduced wait time so the GC
++  // can be performed more early for all dirty contexts. The flag is set
++  // to false again once all contexts have been cleaned up and there is nothing
++  // more to do
++  bool useReducedWait = false;
++
++  // the time we'll wait for a signal
++  uint64_t regularWaitTime = (uint64_t) (_gcFrequency * 1000.0 * 1000.0);
++
++  // the time we'll wait for a signal when the previous wait timed out
++  uint64_t reducedWaitTime = (uint64_t) (_gcFrequency * 1000.0 * 100.0);
 +
    while (_stopping == 0) {
      V8Context* context = 0;

 
       if (_dirtyContexts.empty()) {
-        guard.wait();
+        // check whether we got a wait timeout or a signal
+        gotSignal = guard.wait(waitTime);
       }
 
       if (! _dirtyContexts.empty()) {
         context = _dirtyContexts.back();
         _dirtyContexts.pop_back();
       }
+
+      if (context == 0 && ! gotSignal && ! _freeContexts.empty()) {
+        // we timed out waiting for a signal
+        // so we'll pop one of the free contexts and clean it up pro-actively
+        context = _freeContexts.back();
+        if (context != 0) {
+          _freeContexts.pop_back();
+        }
+      }
     }
+   
+    // update last gc time   

 
     if (context != 0) {
       LOGGER_TRACE << "collecting V8 garbage";
@@ -288,6 +414,7 @@ void ApplicationV8::collectGarbage () {
       delete context->_locker;
 
       context->_dirt = 0;
