diff --git a/benchmarks/MongoDB.Driver.Benchmarks/README.md b/benchmarks/MongoDB.Driver.Benchmarks/README.md
index fa07012c742..005c5bd5be6 100644
--- a/benchmarks/MongoDB.Driver.Benchmarks/README.md
+++ b/benchmarks/MongoDB.Driver.Benchmarks/README.md
@@ -1,6 +1,6 @@
 # C# Driver Benchmark Suite
 
-This suite implements the benchmarks described in this [spec](https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.rst).
+This suite implements the benchmarks described in this [spec](https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.md).
 
 ## Running the Driver Benchmarks
 
@@ -13,7 +13,7 @@ This suite implements the benchmarks described in this [spec](https://github.com
    (e.g `dotnet run -c Release -- --driverBenchmarks --envVars MONGODB_URI:"ConnectionString"`)
 
 You can also select the benchmarks to run directly on the command for running the benchmarks as such
-`dotnet run -c Release -- --driverBenchmarks --fitler "*BenchmarkClassName*"`. The benchmarks are also grouped into categories namely: BSONBench, WriteBench
+`dotnet run -c Release -- --driverBenchmarks --filter "*BenchmarkClassName*"`. The benchmarks are also grouped into categories namely: BSONBench, WriteBench
 ReadBench, ParallelBench, SingleBench, MultiBench and DriverBench. So if you wanted to only run the WriteBench benchmarks, you can do so
 as follows: `dotnet run -c Release -- --driverBenchmarks --anyCategories "WriteBench"`.
 
diff --git a/src/MongoDB.Bson/IO/BsonBinaryReader.cs b/src/MongoDB.Bson/IO/BsonBinaryReader.cs
index 3bf194cd425..4993bffd764 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryReader.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryReader.cs
@@ -432,7 +432,7 @@ public override string ReadJavaScriptWithScope()
 
             var startPosition = _bsonStream.Position; // position of size field
             var size = ReadSize();
-            _context = new BsonBinaryReaderContext(_context, ContextType.JavaScriptWithScope, startPosition, size);
+            _context = _context.PushContext(ContextType.JavaScriptWithScope, startPosition, size);
             var code = _bsonStream.ReadString(Settings.Encoding);
 
             State = BsonReaderState.ScopeDocument;
@@ -590,7 +590,7 @@ public override void ReadStartArray()
 
             var startPosition = _bsonStream.Position; // position of size field
             var size = ReadSize();
-            _context = new BsonBinaryReaderContext(_context, ContextType.Array, startPosition, size);
+            _context = _context.PushContext(ContextType.Array, startPosition, size);
             State = BsonReaderState.Type;
         }
 
@@ -605,7 +605,7 @@ public override void ReadStartDocument()
             var contextType = (State == BsonReaderState.ScopeDocument) ? ContextType.ScopeDocument : ContextType.Document;
             var startPosition = _bsonStream.Position; // position of size field
             var size = ReadSize();
-            _context = new BsonBinaryReaderContext(_context, contextType, startPosition, size);
+            _context = _context.PushContext(contextType, startPosition, size);
             State = BsonReaderState.Type;
         }
 
diff --git a/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs b/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs
index c4e18381dda..589362a24de 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs
@@ -21,9 +21,10 @@ internal class BsonBinaryReaderContext
     {
         // private fields
         private readonly BsonBinaryReaderContext _parentContext;
-        private readonly ContextType _contextType;
-        private readonly long _startPosition;
-        private readonly long _size;
+        private BsonBinaryReaderContext _cachedPushContext;
+        private ContextType _contextType;
+        private long _startPosition;
+        private long _size;
         private string _currentElementName;
         private int _currentArrayIndex = -1;
 
@@ -83,5 +84,20 @@ public BsonBinaryReaderContext PopContext(long position)
             }
             return _parentContext;
         }
+
+        internal BsonBinaryReaderContext PushContext(ContextType contextType, long startPosition, long size)
+        {
+            if (_cachedPushContext == null)
+                _cachedPushContext = new BsonBinaryReaderContext(this, contextType, startPosition, size);
+            else
+            {
+                _cachedPushContext._contextType = contextType;
+                _cachedPushContext._startPosition = startPosition;
+                _cachedPushContext._size = size;
+                _cachedPushContext._currentArrayIndex = -1;
+                _cachedPushContext._currentElementName = null;
+            }
+            return _cachedPushContext;
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriter.cs b/src/MongoDB.Bson/IO/BsonBinaryWriter.cs
index 42430ef4eb4..b1535347d79 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryWriter.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryWriter.cs
@@ -290,7 +290,7 @@ public override void WriteEndArray()
             _bsonStream.WriteByte(0);
             BackpatchSize(); // size of document
 
-            _context = _context.ParentContext;
+            _context = _context.PopContext();
             State = GetNextState();
         }
 
@@ -313,7 +313,7 @@ public override void WriteEndDocument()
             _bsonStream.WriteByte(0);
             BackpatchSize(); // size of document
 
-            _context = _context.ParentContext;
+            _context = _context.PopContext();
             if (_context == null)
             {
                 State = BsonWriterState.Done;
@@ -323,7 +323,7 @@ public override void WriteEndDocument()
                 if (_context.ContextType == ContextType.JavaScriptWithScope)
                 {
                     BackpatchSize(); // size of the JavaScript with scope value
-                    _context = _context.ParentContext;
+                    _context = _context.PopContext();
                 }
                 State = GetNextState();
             }
@@ -400,7 +400,7 @@ public override void WriteJavaScriptWithScope(string code)
 
             _bsonStream.WriteBsonType(BsonType.JavaScriptWithScope);
             WriteNameHelper();
-            _context = new BsonBinaryWriterContext(_context, ContextType.JavaScriptWithScope, _bsonStream.Position);
+            _context = _context.PushContext(ContextType.JavaScriptWithScope, _bsonStream.Position);
             _bsonStream.WriteInt32(0); // reserve space for size of JavaScript with scope value
             _bsonStream.WriteString(code, Settings.Encoding);
 
@@ -564,7 +564,7 @@ public override void WriteStartArray()
             base.WriteStartArray();
             _bsonStream.WriteBsonType(BsonType.Array);
             WriteNameHelper();
-            _context = new BsonBinaryWriterContext(_context, ContextType.Array, _bsonStream.Position);
+            _context = _context.PushContext(ContextType.Array, _bsonStream.Position);
             _bsonStream.WriteInt32(0); // reserve space for size
 
             State = BsonWriterState.Value;
@@ -588,7 +588,10 @@ public override void WriteStartDocument()
                 WriteNameHelper();
             }
             var contextType = (State == BsonWriterState.ScopeDocument) ? ContextType.ScopeDocument : ContextType.Document;
-            _context = new BsonBinaryWriterContext(_context, contextType, _bsonStream.Position);
+            if (_context == null)
+                _context = new BsonBinaryWriterContext(null, contextType, _bsonStream.Position);
+            else
+                _context = _context.PushContext(contextType, _bsonStream.Position);
             _bsonStream.WriteInt32(0); // reserve space for size
 
             State = BsonWriterState.Name;
diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs b/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
index fb791ab4fc3..8512e9d56de 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
@@ -18,7 +18,8 @@ namespace MongoDB.Bson.IO
     internal class BsonBinaryWriterContext
     {
         // private fields
-        private BsonBinaryWriterContext _parentContext;
+        private readonly BsonBinaryWriterContext _parentContext;
+        private BsonBinaryWriterContext _cachedPushContext;
         private ContextType _contextType;
         private long _startPosition;
         private int _index; // used when contextType is Array
@@ -55,5 +56,23 @@ internal int Index
             get { return _index; }
             set { _index = value; }
         }
+
+        internal BsonBinaryWriterContext PopContext()
+        {
+            return _parentContext;
+        }
+
+        internal BsonBinaryWriterContext PushContext(ContextType contextType, long startPosition)
+        {
+            if (_cachedPushContext == null)
+                _cachedPushContext = new BsonBinaryWriterContext(this, contextType, startPosition);
+            else
+            {
+                _cachedPushContext._contextType = contextType;
+                _cachedPushContext._startPosition = startPosition;
+                _cachedPushContext._index = 0;
+            }
+            return _cachedPushContext;
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/BsonDocumentReader.cs b/src/MongoDB.Bson/IO/BsonDocumentReader.cs
index aa4a1e93252..2231bee8be0 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentReader.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentReader.cs
@@ -413,7 +413,7 @@ public override void ReadStartArray()
             VerifyBsonType("ReadStartArray", BsonType.Array);
 
             var array = _currentValue.AsBsonArray;
-            _context = new BsonDocumentReaderContext(_context, ContextType.Array, array);
+            _context = _context.PushContext(ContextType.Array, array);
             State = BsonReaderState.Type;
         }
 
@@ -435,7 +435,7 @@ public override void ReadStartDocument()
             {
                 document = _currentValue.AsBsonDocument;
             }
-            _context = new BsonDocumentReaderContext(_context, ContextType.Document, document);
+            _context = _context.PushContext(ContextType.Document, document);
             State = BsonReaderState.Type;
         }
 
diff --git a/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs b/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs
index 9208be4ae0f..aa5013eb5ee 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs
@@ -18,20 +18,23 @@ namespace MongoDB.Bson.IO
     internal class BsonDocumentReaderContext
     {
         // private fields
-        private BsonDocumentReaderContext _parentContext;
+        private readonly BsonDocumentReaderContext _parentContext;
+        private BsonDocumentReaderContext _cachedPushContext;
         private ContextType _contextType;
         private BsonDocument _document;
         private BsonArray _array;
         private int _index;
 
         // constructors
-        internal BsonDocumentReaderContext(
+        private BsonDocumentReaderContext(
             BsonDocumentReaderContext parentContext,
             ContextType contextType,
+            BsonDocument document,
             BsonArray array)
         {
             _parentContext = parentContext;
             _contextType = contextType;
+            _document = document;
             _array = array;
         }
 
@@ -124,5 +127,29 @@ public BsonDocumentReaderContext PopContext()
         {
             return _parentContext;
         }
+
+        internal BsonDocumentReaderContext PushContext(ContextType contextType, BsonArray array)
+        {
+            return PushContext(contextType, null, array);
+        }
+
+        internal BsonDocumentReaderContext PushContext(ContextType contextType, BsonDocument document)
+        {
+            return PushContext(contextType, document, null);
+        }
+
+        private BsonDocumentReaderContext PushContext(ContextType contextType, BsonDocument document, BsonArray array)
+        {
+            if (_cachedPushContext == null)
+                _cachedPushContext = new BsonDocumentReaderContext(this, contextType, document, array);
+            else
+            {
+                _cachedPushContext._contextType = contextType;
+                _cachedPushContext._document = document;
+                _cachedPushContext._array = array;
+                _cachedPushContext._index = 0;
+            }
+            return _cachedPushContext;
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/BsonDocumentWriter.cs b/src/MongoDB.Bson/IO/BsonDocumentWriter.cs
index 3f77160f1c2..8e5e4ef0b27 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentWriter.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentWriter.cs
@@ -195,7 +195,7 @@ public override void WriteEndArray()
 
             base.WriteEndArray();
             var array = _context.Array;
-            _context = _context.ParentContext;
+            _context = _context.PopContext();
             WriteValue(array);
             State = GetNextState();
         }
@@ -219,15 +219,15 @@ public override void WriteEndDocument()
             if (_context.ContextType == ContextType.ScopeDocument)
             {
                 var scope = _context.Document;
-                _context = _context.ParentContext;
+                _context = _context.PopContext();
                 var code = _context.Code;
-                _context = _context.ParentContext;
+                _context = _context.PopContext();
                 WriteValue(new BsonJavaScriptWithScope(code, scope));
             }
             else
             {
                 var document = _context.Document;
-                _context = _context.ParentContext;
+                _context = _context.PopContext();
                 if (_context != null)
                 {
                     WriteValue(document);
@@ -304,7 +304,7 @@ public override void WriteJavaScriptWithScope(string code)
                 ThrowInvalidState("WriteJavaScriptWithScope", BsonWriterState.Value);
             }
 
-            _context = new BsonDocumentWriterContext(_context, ContextType.JavaScriptWithScope, code);
+            _context = _context.PushContext(ContextType.JavaScriptWithScope, code);
             State = BsonWriterState.ScopeDocument;
         }
 
@@ -407,7 +407,7 @@ public override void WriteStartArray()
             }
 
             base.WriteStartArray();
-            _context = new BsonDocumentWriterContext(_context, ContextType.Array, new BsonArray());
+            _context = _context.PushContext(ContextType.Array, new BsonArray());
             State = BsonWriterState.Value;
         }
 
@@ -430,10 +430,10 @@ public override void WriteStartDocument()
                     _context = new BsonDocumentWriterContext(null, ContextType.Document, _document);
                     break;
                 case BsonWriterState.Value:
-                    _context = new BsonDocumentWriterContext(_context, ContextType.Document, new BsonDocument());
+                    _context = _context.PushContext(ContextType.Document, new BsonDocument());
                     break;
                 case BsonWriterState.ScopeDocument:
-                    _context = new BsonDocumentWriterContext(_context, ContextType.ScopeDocument, new BsonDocument());
+                    _context = _context.PushContext(ContextType.ScopeDocument, new BsonDocument());
                     break;
                 default:
                     throw new BsonInternalException("Unexpected state.");
diff --git a/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs b/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
index 4aa1f6ddd82..00f25a8e790 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
@@ -18,7 +18,8 @@ namespace MongoDB.Bson.IO
     internal class BsonDocumentWriterContext
     {
         // private fields
-        private BsonDocumentWriterContext _parentContext;
+        private readonly BsonDocumentWriterContext _parentContext;
+        private BsonDocumentWriterContext _cachedPushContext;
         private ContextType _contextType;
         private BsonDocument _document;
         private BsonArray _array;
@@ -36,23 +37,17 @@ internal BsonDocumentWriterContext(
             _document = document;
         }
 
-        internal BsonDocumentWriterContext(
-            BsonDocumentWriterContext parentContext,
-            ContextType contextType,
-            BsonArray array)
-        {
-            _parentContext = parentContext;
-            _contextType = contextType;
-            _array = array;
-        }
-
-        internal BsonDocumentWriterContext(
+        private BsonDocumentWriterContext(
             BsonDocumentWriterContext parentContext,
             ContextType contextType,
+            BsonDocument document,
+            BsonArray array,
             string code)
         {
             _parentContext = parentContext;
             _contextType = contextType;
+            _document = document;
+            _array = array;
             _code = code;
         }
 
@@ -87,5 +82,40 @@ internal string Code
         {
             get { return _code; }
         }
+
+        internal BsonDocumentWriterContext PopContext()
+        {
+            return _parentContext;
+        }
+
+        internal BsonDocumentWriterContext PushContext(ContextType contextType, BsonDocument document)
+        {
+            return PushContext(contextType, document, null, null);
+        }
+
+        internal BsonDocumentWriterContext PushContext(ContextType contextType, BsonArray array)
+        {
+            return PushContext(contextType, null, array, null);
+        }
+
+        internal BsonDocumentWriterContext PushContext(ContextType contextType, string code)
+        {
+            return PushContext(contextType, null, null, code);
+        }
+
+        private BsonDocumentWriterContext PushContext(ContextType contextType, BsonDocument document, BsonArray array, string code)
+        {
+            if (_cachedPushContext == null)
+                _cachedPushContext = new BsonDocumentWriterContext(this, contextType, document, array, code);
+            else
+            {
+                _cachedPushContext._contextType = contextType;
+                _cachedPushContext._document = document;
+                _cachedPushContext._array = array;
+                _cachedPushContext._code = code;
+                _cachedPushContext._name = null;
+            }
+            return _cachedPushContext;
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/JsonReader.cs b/src/MongoDB.Bson/IO/JsonReader.cs
index 0d5a483ff60..d26f7846b7c 100644
--- a/src/MongoDB.Bson/IO/JsonReader.cs
+++ b/src/MongoDB.Bson/IO/JsonReader.cs
@@ -627,7 +627,7 @@ public override string ReadJavaScriptWithScope()
         {
             if (Disposed) { ThrowObjectDisposedException(); }
             VerifyBsonType("ReadJavaScriptWithScope", BsonType.JavaScriptWithScope);
-            _context = new JsonReaderContext(_context, ContextType.JavaScriptWithScope);
+            _context = _context.PushContext(ContextType.JavaScriptWithScope);
             State = BsonReaderState.ScopeDocument;
             return _currentValue.AsString;
         }
@@ -723,7 +723,7 @@ public override void ReadStartArray()
             if (Disposed) { ThrowObjectDisposedException(); }
             VerifyBsonType("ReadStartArray", BsonType.Array);
 
-            _context = new JsonReaderContext(_context, ContextType.Array);
+            _context = _context.PushContext(ContextType.Array);
             State = BsonReaderState.Type;
         }
 
@@ -735,7 +735,7 @@ public override void ReadStartDocument()
             if (Disposed) { ThrowObjectDisposedException(); }
             VerifyBsonType("ReadStartDocument", BsonType.Document);
 
-            _context = new JsonReaderContext(_context, ContextType.Document);
+            _context = _context.PushContext(ContextType.Document);
             State = BsonReaderState.Type;
         }
 
diff --git a/src/MongoDB.Bson/IO/JsonReaderContext.cs b/src/MongoDB.Bson/IO/JsonReaderContext.cs
index 94dc554ec39..e93707a4bae 100644
--- a/src/MongoDB.Bson/IO/JsonReaderContext.cs
+++ b/src/MongoDB.Bson/IO/JsonReaderContext.cs
@@ -18,7 +18,8 @@ namespace MongoDB.Bson.IO
     internal class JsonReaderContext
     {
         // private fields
-        private JsonReaderContext _parentContext;
+        private readonly JsonReaderContext _parentContext;
+        private JsonReaderContext _cachedPushContext;
         private ContextType _contextType;
 
         // constructors
@@ -53,5 +54,14 @@ public JsonReaderContext PopContext()
         {
             return _parentContext;
         }
+
+        internal JsonReaderContext PushContext(ContextType contextType)
+        {
+            if (_cachedPushContext == null)
+                _cachedPushContext = new JsonReaderContext(this, contextType);
+            else
+                _cachedPushContext._contextType = contextType;
+            return _cachedPushContext;
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/JsonWriter.cs b/src/MongoDB.Bson/IO/JsonWriter.cs
index 39b884c8618..501cfc4ad01 100644
--- a/src/MongoDB.Bson/IO/JsonWriter.cs
+++ b/src/MongoDB.Bson/IO/JsonWriter.cs
@@ -312,7 +312,7 @@ public override void WriteEndArray()
             base.WriteEndArray();
             _textWriter.Write("]");
 
-            _context = _context.ParentContext;
+            _context = _context.PopContext();
             State = GetNextState();
         }
 
@@ -344,12 +344,12 @@ public override void WriteEndDocument()
 
             if (_context.ContextType == ContextType.ScopeDocument)
             {
-                _context = _context.ParentContext;
+                _context = _context.PopContext();
                 WriteEndDocument();
             }
             else
             {
-                _context = _context.ParentContext;
+                _context = _context.PopContext();
             }
 
             if (_context == null)
@@ -641,7 +641,7 @@ public override void WriteStartArray()
             WriteNameHelper(Name);
             _textWriter.Write("[");
 
-            _context = new JsonWriterContext(_context, ContextType.Array, Settings.IndentChars);
+            _context = _context.PushContext(ContextType.Array, Settings.IndentChars);
             State = BsonWriterState.Value;
         }
 
@@ -664,7 +664,7 @@ public override void WriteStartDocument()
             _textWriter.Write("{");
 
             var contextType = (State == BsonWriterState.ScopeDocument) ? ContextType.ScopeDocument : ContextType.Document;
-            _context = new JsonWriterContext(_context, contextType, Settings.IndentChars);
+            _context = _context.PushContext(contextType, Settings.IndentChars);
             State = BsonWriterState.Name;
         }
 
diff --git a/src/MongoDB.Bson/IO/JsonWriterContext.cs b/src/MongoDB.Bson/IO/JsonWriterContext.cs
index c48dc7cef12..cdc8b6c2cee 100644
--- a/src/MongoDB.Bson/IO/JsonWriterContext.cs
+++ b/src/MongoDB.Bson/IO/JsonWriterContext.cs
@@ -18,7 +18,8 @@ namespace MongoDB.Bson.IO
     internal class JsonWriterContext
     {
         // private fields
-        private JsonWriterContext _parentContext;
+        private readonly JsonWriterContext _parentContext;
+        private JsonWriterContext _cachedPushContext;
         private ContextType _contextType;
         private string _indentation;
         private bool _hasElements = false;
@@ -52,5 +53,22 @@ internal bool HasElements
             get { return _hasElements; }
             set { _hasElements = value; }
         }
+
+        internal JsonWriterContext PopContext()
+        {
+            return _parentContext;
+        }
+
+        internal JsonWriterContext PushContext(ContextType contextType, string indentChars)
+        {
+            if (_cachedPushContext == null)
+                _cachedPushContext = new JsonWriterContext(this, contextType, indentChars);
+            else
+            {
+                _cachedPushContext._contextType = contextType;
+                _cachedPushContext._hasElements = false;
+            }
+            return _cachedPushContext;
+        }
     }
 }