diff --git a/CHANGES.txt b/CHANGES.txt
index 542041c0697ec76074c5d7d7134a31dc43f96044_Q0hBTkdFUy50eHQ=..cbc08130cbdbb1db786080b4eabbcd45fc2b5a1e_Q0hBTkdFUy50eHQ= 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,8 @@
 Version 2.1.0 released XXXX-XX-XX
 
+* Memoization of object keys during encoding (when using speedups)
+* Encoder changed to use PyIter_Next for list iteration to avoid
+  potential threading issues
 * Encoder changed to use iteritems rather than PyDict_Next in order to
   support dict subclasses that have a well defined ordering
   http://bugs.python.org/issue6105
diff --git a/simplejson/_speedups.c b/simplejson/_speedups.c
index 542041c0697ec76074c5d7d7134a31dc43f96044_c2ltcGxlanNvbi9fc3BlZWR1cHMuYw==..cbc08130cbdbb1db786080b4eabbcd45fc2b5a1e_c2ltcGxlanNvbi9fc3BlZWR1cHMuYw== 100644
--- a/simplejson/_speedups.c
+++ b/simplejson/_speedups.c
@@ -77,6 +77,7 @@
     PyObject *item_separator;
     PyObject *sort_keys;
     PyObject *skipkeys;
+    PyObject *key_memo;
     int fast_encode;
     int allow_nan;
 } PyEncoderObject;
@@ -90,6 +91,7 @@
     {"item_separator", T_OBJECT, offsetof(PyEncoderObject, item_separator), READONLY, "item_separator"},
     {"sort_keys", T_OBJECT, offsetof(PyEncoderObject, sort_keys), READONLY, "sort_keys"},
     {"skipkeys", T_OBJECT, offsetof(PyEncoderObject, skipkeys), READONLY, "skipkeys"},
+    {"key_memo", T_OBJECT, offsetof(PyEncoderObject, key_memo), READONLY, "key_memo"},
     {NULL}
 };
 
@@ -1864,6 +1866,7 @@
         s->item_separator = NULL;
         s->sort_keys = NULL;
         s->skipkeys = NULL;
+        s->key_memo = NULL;
     }
     return (PyObject *)s;
 }
@@ -1872,7 +1875,7 @@
 encoder_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
     /* initialize Encoder object */
-    static char *kwlist[] = {"markers", "default", "encoder", "indent", "key_separator", "item_separator", "sort_keys", "skipkeys", "allow_nan", NULL};
+    static char *kwlist[] = {"markers", "default", "encoder", "indent", "key_separator", "item_separator", "sort_keys", "skipkeys", "allow_nan", "key_memo", NULL};
 
     PyEncoderObject *s;
     PyObject *markers, *defaultfn, *encoder, *indent, *key_separator;
@@ -1876,8 +1879,8 @@
 
     PyEncoderObject *s;
     PyObject *markers, *defaultfn, *encoder, *indent, *key_separator;
-    PyObject *item_separator, *sort_keys, *skipkeys, *allow_nan;
+    PyObject *item_separator, *sort_keys, *skipkeys, *allow_nan, *key_memo;
 
     assert(PyEncoder_Check(self));
     s = (PyEncoderObject *)self;
 
@@ -1880,6 +1883,6 @@
 
     assert(PyEncoder_Check(self));
     s = (PyEncoderObject *)self;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOOOOOO:make_encoder", kwlist,
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOOOOOOO:make_encoder", kwlist,
         &markers, &defaultfn, &encoder, &indent, &key_separator, &item_separator,
@@ -1885,5 +1888,5 @@
         &markers, &defaultfn, &encoder, &indent, &key_separator, &item_separator,
-        &sort_keys, &skipkeys, &allow_nan))
+        &sort_keys, &skipkeys, &allow_nan, &key_memo))
         return -1;
 
     s->markers = markers;
@@ -1894,6 +1897,7 @@
     s->item_separator = item_separator;
     s->sort_keys = sort_keys;
     s->skipkeys = skipkeys;
+    s->key_memo = key_memo;
     s->fast_encode = (PyCFunction_Check(s->encoder) && PyCFunction_GetFunction(s->encoder) == (PyCFunction)py_encode_basestring_ascii);
     s->allow_nan = PyObject_IsTrue(allow_nan);
 
@@ -1905,6 +1909,7 @@
     Py_INCREF(s->item_separator);
     Py_INCREF(s->sort_keys);
     Py_INCREF(s->skipkeys);
+    Py_INCREF(s->key_memo);
     return 0;
 }
 
@@ -2101,6 +2106,7 @@
     PyObject *key, *value;
     PyObject *iter = NULL;
     PyObject *item = NULL;
+    PyObject *encoded = NULL;
     int skipkeys;
     Py_ssize_t idx;
 
@@ -2152,7 +2158,6 @@
     if (iter == NULL)
         goto bail;
     while ((item = PyIter_Next(iter))) {
-        PyObject *encoded;
 
         key = PyTuple_GetItem(item, 0);
         if (key == NULL)
@@ -2160,8 +2165,12 @@
         value = PyTuple_GetItem(item, 1);
         if (value == NULL)
             goto bail;
-
-        if (PyString_Check(key) || PyUnicode_Check(key)) {
+        
+        encoded = PyDict_GetItem(s->key_memo, key);
+        if (encoded != NULL) {
+            Py_INCREF(encoded);
+        }
+        else if (PyString_Check(key) || PyUnicode_Check(key)) {
             Py_INCREF(key);
             kstr = key;
         }
@@ -2195,8 +2204,12 @@
                 goto bail;
         }
 
-        encoded = encoder_encode_string(s, kstr);
-        Py_CLEAR(kstr);
-        if (encoded == NULL)
-            goto bail;
+        if (encoded == NULL) {
+            encoded = encoder_encode_string(s, kstr);
+            Py_CLEAR(kstr);
+            if (encoded == NULL)
+                goto bail;
+            if (PyDict_SetItem(s->key_memo, key, encoded))
+                goto bail;
+        }
         if (PyList_Append(rval, encoded)) {
@@ -2202,4 +2215,3 @@
         if (PyList_Append(rval, encoded)) {
-            Py_DECREF(encoded);
             goto bail;
         }
@@ -2204,6 +2216,6 @@
             goto bail;
         }
-        Py_DECREF(encoded);
+        Py_CLEAR(encoded);
         if (PyList_Append(rval, s->key_separator))
             goto bail;
         if (encoder_listencode_obj(s, rval, value, indent_level))
@@ -2231,6 +2243,7 @@
     return 0;
 
 bail:
+    Py_XDECREF(encoded);
     Py_XDECREF(item);
     Py_XDECREF(iter);
     Py_XDECREF(kstr);
@@ -2355,6 +2368,7 @@
     Py_VISIT(s->item_separator);
     Py_VISIT(s->sort_keys);
     Py_VISIT(s->skipkeys);
+    Py_VISIT(s->key_memo);
     return 0;
 }
 
@@ -2373,6 +2387,7 @@
     Py_CLEAR(s->item_separator);
     Py_CLEAR(s->sort_keys);
     Py_CLEAR(s->skipkeys);
+    Py_CLEAR(s->key_memo);
     return 0;
 }
 
diff --git a/simplejson/encoder.py b/simplejson/encoder.py
index 542041c0697ec76074c5d7d7134a31dc43f96044_c2ltcGxlanNvbi9lbmNvZGVyLnB5..cbc08130cbdbb1db786080b4eabbcd45fc2b5a1e_c2ltcGxlanNvbi9lbmNvZGVyLnB5 100644
--- a/simplejson/encoder.py
+++ b/simplejson/encoder.py
@@ -261,8 +261,9 @@
             return text
 
 
+        key_memo = {}
         if (_one_shot and c_make_encoder is not None
                 and not self.indent and not self.sort_keys):
             _iterencode = c_make_encoder(
                 markers, self.default, _encoder, self.indent,
                 self.key_separator, self.item_separator, self.sort_keys,
@@ -264,11 +265,11 @@
         if (_one_shot and c_make_encoder is not None
                 and not self.indent and not self.sort_keys):
             _iterencode = c_make_encoder(
                 markers, self.default, _encoder, self.indent,
                 self.key_separator, self.item_separator, self.sort_keys,
-                self.skipkeys, self.allow_nan)
+                self.skipkeys, self.allow_nan, key_memo)
         else:
             _iterencode = _make_iterencode(
                 markers, self.default, _encoder, self.indent, floatstr,
                 self.key_separator, self.item_separator, self.sort_keys,
                 self.skipkeys, _one_shot)
@@ -270,9 +271,12 @@
         else:
             _iterencode = _make_iterencode(
                 markers, self.default, _encoder, self.indent, floatstr,
                 self.key_separator, self.item_separator, self.sort_keys,
                 self.skipkeys, _one_shot)
-        return _iterencode(o, 0)
+        try:
+            return _iterencode(o, 0)
+        finally:
+            key_memo.clear()
 
 def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
         _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,