diff --git a/includes/cache.inc b/includes/cache.inc
index a19d3c3..57a1416 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -344,9 +344,6 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
    */
   function getMultiple(&$cids) {
     try {
-      // Garbage collection necessary when enforcing a minimum cache lifetime.
-      $this->garbageCollection($this->bin);
-
       // When serving cached pages, the overhead of using db_select() was found
       // to add around 30% overhead to the request. Since $this->bin is a
       // variable, this means the call to db_query() here uses a concatenated
@@ -400,18 +397,8 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
     if (!$cache_lifetime) {
       return;
     }
-    // When cache lifetime is in force, avoid running garbage collection too
-    // often since this will remove temporary cache items indiscriminately.
-    $cache_flush = variable_get('cache_flush_' . $this->bin, 0);
-    if ($cache_flush && ($cache_flush + $cache_lifetime <= REQUEST_TIME)) {
-      // Reset the variable immediately to prevent a meltdown in heavy load situations.
-      variable_set('cache_flush_' . $this->bin, 0);
-      // Time to flush old cache data
-      db_delete($this->bin)
-        ->condition('expire', CACHE_PERMANENT, '<>')
-        ->condition('expire', $cache_flush, '<=')
-        ->execute();
-    }
+
+    $this->clear();
   }
 
   /**
@@ -486,29 +473,27 @@ class DrupalDatabaseCache implements DrupalCacheInterface {
     global $user;
 
     if (empty($cid)) {
-      if (variable_get('cache_lifetime', 0)) {
+      if ($cache_lifetime = variable_get('cache_lifetime', 0)) {
         // We store the time in the current user's session. We then simulate
         // that the cache was flushed for this user by not returning cached
         // data that was cached before the timestamp.
         $_SESSION['cache_expiration'][$this->bin] = REQUEST_TIME;
 
-        $cache_flush = variable_get('cache_flush_' . $this->bin, 0);
-        if ($cache_flush == 0) {
-          // This is the first request to clear the cache, start a timer.
-          variable_set('cache_flush_' . $this->bin, REQUEST_TIME);
-        }
-        elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) {
-          // Clear the cache for everyone, cache_lifetime seconds have
-          // passed since the first request to clear the cache.
-          db_delete($this->bin)
-            ->condition('expire', CACHE_PERMANENT, '<>')
-            ->condition('expire', REQUEST_TIME, '<')
-            ->execute();
-          variable_set('cache_flush_' . $this->bin, 0);
-        }
+      // Clear expired items from the cache.
+      db_delete($this->bin)
+        ->condition('expire', CACHE_PERMANENT, '>')
+        ->condition('expire', REQUEST_TIME, '<')
+        ->execute();
+      variable_set('cache_flush_' . $this->bin, 0);
+
+      // Clear CACHE_TEMPORARY items older than the minimum cache lifetime.
+      db_delete($this->bin)
+        ->condition('expire', CACHE_TEMPORARY)
+        ->condition('created', REQUEST_TIME - $cache_lifetime, '<')
+        ->execute();
       }
       else {
-        // No minimum cache lifetime, flush all temporary cache entries now.
+        // No minimum cache lifetime, flush all expired & temporary entries now.
         db_delete($this->bin)
           ->condition('expire', CACHE_PERMANENT, '<>')
           ->condition('expire', REQUEST_TIME, '<')
diff --git a/modules/system/system.install b/modules/system/system.install
index ad15851..ca6000c 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -684,7 +684,7 @@ function system_schema() {
       ),
     ),
     'indexes' => array(
-      'expire' => array('expire'),
+      'expire_created' => array('expire', 'created'),
     ),
     'primary key' => array('cid'),
   );
@@ -3016,6 +3016,22 @@ function system_update_7073() {
 }
 
 /**
+ * Update all cache tables to use expire and created for their indexes.
+ */
+function system_update_7074() {
+  // Define the new index.
+  $fields = array('expire', 'created');
+
+  // Get a list of all cache tables.
+  $core = array('cache', 'cache_form', 'cache_path', 'cache_filter', 'cache_bootstrap', 'cache_page');
+  $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
+  foreach ($cache_tables as $bin) {
+    db_drop_index($bin, 'expire');
+    db_add_index($bin, 'expire_created', $fields)
+  }
+}
+
+/**
  * @} End of "defgroup updates-7.x-extra".
  * The next series of updates should start at 8000.
  */
diff --git a/modules/system/system.module b/modules/system/system.module
index 072850e..4ef24f1 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -3037,7 +3037,22 @@ function system_cron() {
   $core = array('cache', 'cache_path', 'cache_filter', 'cache_page', 'cache_form', 'cache_menu');
   $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
   foreach ($cache_tables as $table) {
-    cache_clear_all(NULL, $table);
+    // If the cache backend provides a garbageCollection() method, call that.
+    // If it does not, expire all temporary and expired cache items. Limit
+    // these calls to once every 24 hours by default to avoid wiping the page
+    // and block caches every cron run.
+    $cache = cache($bin);
+    $name = 'cache_garbage_collect_' . $bin;
+    $window = max(variable_get('cache_lifetime', 0), variable_get('cache_garbage_collection_frequency', 86400));
+    if (flood_is_allowed($name, 1, $window, 'cron')) {
+      flood_register_event($name, 1, $window, 'cron');
+      if (method_exists($cache, 'garbageCollection')) {
+        $cache->garbageCollection();
+      }
+      else {
+        $cache->clear();
+      }
+    }
   }
 
   // Cleanup the batch table and the queue for failed batches.
