diff --git a/.gitignore b/.gitignore
index 31124451768e968afa52fc5929c564006ec0f007..06a3d25c3d563026f43a421185a5b8ad2345fcf4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,7 +31,7 @@ coverage
 # python compiled objects
 *.pyc
 
-#eclipse project files
+# eclipse project files
 .cproject
 .project
 .settings
@@ -110,3 +110,6 @@ bazel-genfiles
 bazel-grpc
 bazel-out
 bazel-testlogs
+
+# Debug output
+gdb.txt
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
index a258ba4063999339b2c5d028eab79dec0a6cc6bc..2b5cce88a4f0e71d09509a2dc9c08b327f1db649 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
@@ -70,6 +70,8 @@ cdef class CompletionQueue:
         operation_call = tag.operation_call
         request_call_details = tag.request_call_details
         request_metadata = tag.request_metadata
+        if request_metadata is not None:
+          request_metadata._claim_slice_ownership()
         batch_operations = tag.batch_operations
         if tag.is_new_request:
           # Stuff in the tag not explicitly handled by us needs to live through
@@ -91,7 +93,7 @@ cdef class CompletionQueue:
       c_deadline = gpr_inf_future(GPR_CLOCK_REALTIME)
       if deadline is not None:
         c_deadline = deadline.c_time
-      
+
       while True:
         c_timeout = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c_increment)
         if gpr_time_cmp(c_timeout, c_deadline) > 0:
@@ -100,7 +102,7 @@ cdef class CompletionQueue:
           self.c_completion_queue, c_timeout, NULL)
         if event.type != GRPC_QUEUE_TIMEOUT or gpr_time_cmp(c_timeout, c_deadline) == 0:
           break;
-        
+
         # Handle any signals
         with gil:
           cpython.PyErr_CheckSignals()
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
index 870da51fa8bad31b61423b8ee6928c8575d2eabd..3644b7cdae5f6120e38c9239254f7e0fb73a8052 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
@@ -77,6 +77,8 @@ cdef class Slice:
   cdef void _assign_slice(self, grpc_slice new_slice) nogil
   @staticmethod
   cdef Slice from_slice(grpc_slice slice)
+  @staticmethod
+  cdef bytes bytes_from_slice(grpc_slice slice)
 
 
 cdef class ByteBuffer:
@@ -113,7 +115,10 @@ cdef class Metadatum:
 cdef class Metadata:
 
   cdef grpc_metadata_array c_metadata_array
+  cdef bint owns_metadata_slices
   cdef object metadata
+  cdef void _claim_slice_ownership(self) nogil
+  cdef void _drop_slice_ownership(self) nogil
 
 
 cdef class Operation:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index b7a75cd97a09f3f2f4d460e6423cf863f4923b56..30e7b9657a96ffb47db5e15e3e67019cc0d8c579 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -189,11 +189,11 @@ cdef class CallDetails:
 
   @property
   def method(self):
-    return Slice.from_slice(self.c_details.method).bytes()
+    return Slice.bytes_from_slice(self.c_details.method)
 
   @property
   def host(self):
-    return Slice.from_slice(self.c_details.host).bytes()
+    return Slice.bytes_from_slice(self.c_details.host)
 
   @property
   def deadline(self):
@@ -251,12 +251,16 @@ cdef class Slice:
     self._assign_slice(slice)
     return self
 
-  def bytes(self):
+  @staticmethod
+  cdef bytes bytes_from_slice(grpc_slice slice):
     with nogil:
-      pointer = grpc_slice_start_ptr(self.c_slice)
-      length = grpc_slice_length(self.c_slice)
+      pointer = grpc_slice_start_ptr(slice)
+      length = grpc_slice_length(slice)
     return (<char *>pointer)[:length]
 
+  def bytes(self):
+    return Slice.bytes_from_slice(self.c_slice)
+
   def __dealloc__(self):
     with nogil:
       grpc_slice_unref(self.c_slice)
@@ -466,13 +470,14 @@ cdef class _MetadataIterator:
 cdef class Metadata:
 
   def __cinit__(self, metadata):
-    grpc_init()
+    with nogil:
+      grpc_init()
+      grpc_metadata_array_init(&self.c_metadata_array)
+    self.owns_metadata_slices = False
     self.metadata = list(metadata)
-    for metadatum in metadata:
+    for metadatum in self.metadata:
       if not isinstance(metadatum, Metadatum):
         raise TypeError("expected list of Metadatum")
-    with nogil:
-      grpc_metadata_array_init(&self.c_metadata_array)
     self.c_metadata_array.count = len(self.metadata)
     self.c_metadata_array.capacity = len(self.metadata)
     with nogil:
@@ -484,23 +489,43 @@ cdef class Metadata:
           (<Metadatum>self.metadata[i]).c_metadata)
 
   def __dealloc__(self):
-    # this frees the allocated memory for the grpc_metadata_array (although
-    # it'd be nice if that were documented somewhere...)
-    # TODO(atash): document this in the C core
-    grpc_metadata_array_destroy(&self.c_metadata_array)
-    grpc_shutdown()
+    with nogil:
+      self._drop_slice_ownership()
+      # this frees the allocated memory for the grpc_metadata_array (although
+      # it'd be nice if that were documented somewhere...)
+      # TODO(atash): document this in the C core
+      grpc_metadata_array_destroy(&self.c_metadata_array)
+      grpc_shutdown()
 
   def __len__(self):
     return self.c_metadata_array.count
 
   def __getitem__(self, size_t i):
+    if i >= self.c_metadata_array.count:
+      raise IndexError
     return Metadatum(
-        key=Slice.from_slice(self.c_metadata_array.metadata[i].key).bytes(),
-        value=Slice.from_slice(self.c_metadata_array.metadata[i].value).bytes())
+        key=Slice.bytes_from_slice(self.c_metadata_array.metadata[i].key),
+        value=Slice.bytes_from_slice(self.c_metadata_array.metadata[i].value))
 
   def __iter__(self):
     return _MetadataIterator(self)
 
+  cdef void _claim_slice_ownership(self) nogil:
+    if self.owns_metadata_slices:
+      return
+    for i in range(self.c_metadata_array.count):
+      grpc_slice_ref(self.c_metadata_array.metadata[i].key)
+      grpc_slice_ref(self.c_metadata_array.metadata[i].value)
+    self.owns_metadata_slices = True
+
+  cdef void _drop_slice_ownership(self) nogil:
+    if not self.owns_metadata_slices:
+      return
+    for i in range(self.c_metadata_array.count):
+      grpc_slice_unref(self.c_metadata_array.metadata[i].key)
+      grpc_slice_unref(self.c_metadata_array.metadata[i].value)
+    self.owns_metadata_slices = False
+
 
 cdef class Operation:
 
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index 5223712dfa7d47d6ce69b9612565bc4615ed393d..75f661340cf73c8adedc07329d1b794da1dbd912 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -576,6 +576,8 @@ def _handle_with_method_handler(rpc_event, method_handler, thread_pool):
 
 
 def _handle_call(rpc_event, generic_handlers, thread_pool):
+  if not rpc_event.success:
+    return None
   if rpc_event.request_call_details.method is not None:
     method_handler = _find_method_handler(rpc_event, generic_handlers)
     if method_handler is None: