diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 9b4667e..0ec70e2 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -939,6 +939,40 @@ function drupal_get_filename($type, $name, $filename = NULL) {
 }
 
 /**
+ * Extends DrupalCacheArray to allow for cumulative caching of variables.
+ */
+class VariableCache extends DrupalCacheArray {
+  protected function resolveCacheMiss($offset) {
+    $result = db_query('SELECT value FROM {variable} WHERE name = :name', array(':name' => $offset))->fetchField();
+    $value = $result ? unserialize($result) : NULL;
+    $this->storage[$offset] = $value;
+    $this->persist($offset);
+    return $value;
+  }
+
+  /**
+   * Replace the storage variable with a separate array.
+   *
+   * @return
+   *   The value of the storage variable before it was replaced.
+   */
+  public function replaceStorage($array) {
+    $return = $this->storage;
+    $this->storage = $array;
+    $this->keysToPersist = array();
+    foreach ($this->keysToPersist as $key => $value) {
+      $this->persist($key, FALSE);
+    }
+    return $return;
+  }
+
+  public function offsetUnset($offset) {
+    unset($this->storage[$offset]);
+    unset($this->keysToPersist[$offset]);
+  }
+}
+
+/**
  * Load the persistent variable table.
  *
  * The variable table is composed of values that have been saved in the table
@@ -946,27 +980,11 @@ function drupal_get_filename($type, $name, $filename = NULL) {
  * file.
  */
 function variable_initialize($conf = array()) {
-  // NOTE: caching the variables improves performance by 20% when serving
-  // cached pages.
-  if ($cached = cache('bootstrap')->get('variables')) {
-    $variables = $cached->data;
-  }
-  else {
-    // Cache miss. Avoid a stampede.
-    $name = 'variable_init';
-    if (!lock_acquire($name, 1)) {
-      // Another request is building the variable cache.
-      // Wait, then re-run this function.
-      lock_wait($name);
-      return variable_initialize($conf);
-    }
-    else {
-      // Proceed with variable rebuild.
-      $variables = array_map('unserialize', db_query('SELECT name, value FROM {variable}')->fetchAllKeyed());
-      cache('bootstrap')->set('variables', $variables);
-      lock_release($name);
-    }
-  }
+  $cache = &drupal_static('variables');
+  $cache = new VariableCache('variables', 'cache_bootstrap');
+  // Copy the cached variables, free memory in the cache array by setting it
+  // to empty.
+  $variables = $cache->replaceStorage(array());
 
   foreach ($conf as $name => $value) {
     $variables[$name] = $value;
@@ -995,8 +1013,15 @@ function variable_initialize($conf = array()) {
  */
 function variable_get($name, $default = NULL) {
   global $conf;
-
-  return isset($conf[$name]) ? $conf[$name] : $default;
+  if (isset($conf[$name])) {
+    return $conf[$name];
+  }
+  $cache = &drupal_static('variables');
+  if (isset($cache) && isset($cache[$name])) {
+    $conf[$name] = $cache[$name];
+    return $conf[$name];
+  }
+  return $default;
 }
 
 /**
@@ -1019,10 +1044,22 @@ function variable_set($name, $value) {
   global $conf;
 
   db_merge('variable')->key(array('name' => $name))->fields(array('value' => serialize($value)))->execute();
-
-  cache('bootstrap')->delete('variables');
-
   $conf[$name] = $value;
+
+  $cache = &drupal_static('variables');
+  if (is_object($cache)) {
+    // Write through to the variable cache.
+    $replace = array();
+    if ($cached = cache('bootstrap')->get('variables')) {
+      $cached->data[$name] = $value;
+      cache('bootstrap')->set('variables', $cached->data);
+      $replace = $cached->data;
+    }
+    $cache->replaceStorage($replace);
+  }
+  else {
+    cache('bootstrap')->delete('variables');
+  }
 }
 
 /**
@@ -1044,9 +1081,19 @@ function variable_del($name) {
   db_delete('variable')
     ->condition('name', $name)
     ->execute();
-  cache('bootstrap')->delete('variables');
-
   unset($conf[$name]);
+
+  $cache = &drupal_static('variables');
+  if (is_object($cache)) {
+    unset($cache[$name]);
+    if ($cached = cache('bootstrap')->get('variables')) {
+      unset($cache->data[$name]);
+      cache('bootstrap')->set('variables', $cached->data);
+    }
+  }
+  else {
+    cache('bootstrap')->delete('variables');
+  }
 }
 
 /**
diff --git a/core/modules/simpletest/tests/batch.test b/core/modules/simpletest/tests/batch.test
index 1e9b31b..3d10b20 100644
--- a/core/modules/simpletest/tests/batch.test
+++ b/core/modules/simpletest/tests/batch.test
@@ -83,6 +83,7 @@ class BatchProcessingTestCase extends DrupalWebTestCase {
     $this->assertBatchMessages($this->_resultMessages('batch_1'), t('Batch for step 1 performed successfully.'));
     $this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), t('Execution order was correct.'));
     $this->assertText('step 2', t('Form is displayed in step 2.'));
+    drupal_static_reset('variables');
 
     // Second step triggers batch 2.
     $this->drupalPost(NULL, array(), 'Submit');
diff --git a/core/modules/simpletest/tests/upgrade/upgrade.test b/core/modules/simpletest/tests/upgrade/upgrade.test
index ffb3a55..b1a0b88 100644
--- a/core/modules/simpletest/tests/upgrade/upgrade.test
+++ b/core/modules/simpletest/tests/upgrade/upgrade.test
@@ -50,6 +50,10 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase {
 
     $this->loadedModules = module_list();
 
+    // Reset all statics and variables to perform tests in a clean environment.
+    $conf = array();
+    drupal_static_reset();
+
     // Generate a temporary prefixed database to ensure that tests have a clean starting point.
     $this->databasePrefix = 'simpletest' . mt_rand(1000, 1000000);
     db_update('simpletest_test_id')
@@ -96,8 +100,6 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase {
     ini_set('log_errors', 1);
     ini_set('error_log', $public_files_directory . '/error.log');
 
-    // Reset all statics and variables to perform tests in a clean environment.
-    $conf = array();
 
     // Load the database from the portable PHP dump.
     // The files can be gzipped.
