Index: src/orca/atspi.py
===================================================================
--- src/orca/atspi.py	(revision 2453)
+++ src/orca/atspi.py	(working copy)
@@ -396,6 +396,7 @@
     # to handle singletons.]]]
     #
     _cache = {}
+    _cacheToStrings = {}
 
     def init(registry):
         """Registers various event listeners with the Registry to keep
@@ -578,6 +579,7 @@
             obj = Accessible._cache[acc]
             if not obj.valid:
                 del Accessible._cache[acc]
+                del Accessible._cacheToStrings[acc]
                 obj = None
 
         if not obj:
@@ -585,6 +587,7 @@
 
         if obj.valid:
             Accessible._cache[acc] = obj
+            Accessible._cacheToStrings[acc] = obj.toString()
         else:
             obj = None
 
@@ -608,6 +611,7 @@
         if acc and Accessible._cache.has_key(acc):
             try:
                 del Accessible._cache[acc]
+                del Accessible._cacheToStrings[acc]
             except:
                 pass
 
Index: src/orca/default.py
===================================================================
--- src/orca/default.py	(revision 2453)
+++ src/orca/default.py	(working copy)
@@ -74,6 +74,10 @@
 
 class Script(script.Script):
 
+    # Used by dumpMemoryStats()
+    #
+    _memoryStatsCache = {}
+
     EMBEDDED_OBJECT_CHARACTER = u'\ufffc'
     NO_BREAK_SPACE_CHARACTER  = u'\u00a0'
 
@@ -457,6 +461,11 @@
                 #
                 _("Toggles whether to read just the current table cell or the whole row."))
 
+        self.inputEventHandlers["dumpMemoryStatsHandler"] = \
+            input_event.InputEventHandler(
+                Script.dumpMemoryStats,
+                _("Write out statistics on current memory usage to stdout."))
+
         self.inputEventHandlers["readCharAttributesHandler"] = \
             input_event.InputEventHandler(
                 Script.readCharAttributes,
@@ -1238,6 +1247,20 @@
 
         keyBindings.add(
             keybindings.KeyBinding(
+                "F12",
+                1 << settings.MODIFIER_ORCA,
+                1 << settings.MODIFIER_ORCA,
+                self.inputEventHandlers["dumpMemoryStatsHandler"]))
+
+        keyBindings.add(
+            keybindings.KeyBinding(
+                "SunF37",
+                1 << settings.MODIFIER_ORCA,
+                1 << settings.MODIFIER_ORCA,
+                self.inputEventHandlers["dumpMemoryStatsHandler"]))
+
+        keyBindings.add(
+            keybindings.KeyBinding(
                 "f",
                 1 << settings.MODIFIER_ORCA,
                 1 << settings.MODIFIER_ORCA,
@@ -2960,6 +2983,38 @@
 
         return True
 
+    def dumpMemoryStats(self, inputEvent=None):
+        """Write out statistics on current memory usage to stdout."""
+
+        print "dumpMemoryStats-----------------START---------------------"
+        print "Size of Accessible._cache: ", len(atspi.Accessible._cache)
+
+        if Script._memoryStatsCache == {}:
+            print "Setting up _memoryStatsCache for the first time."
+            pass
+        else:
+            print "Comparing caches."
+            print "Number of keys: ", len(atspi.Accessible._cache.keys())
+            for key in atspi.Accessible._cache.keys():
+                if not Script._memoryStatsCache.has_key(key):
+                    print "New item found. Key: ", key
+                    try:
+                        obj = atspi.Accessible._cache[key]
+                        print "Accessing object."
+                        print "Name: ", obj.accessibleNameToString()
+                        print "Role: ", obj.role
+                        print "Object: ", \
+                            atspi.Accessible._cacheToStrings[key]
+                    except:
+                        print "\nCaught exception for: ", \
+                            atspi.Accessible._cacheToStrings[key]
+                        debug.printException(debug.LEVEL_OFF)
+
+        print "Copying over cache."
+        Script._memoryStatsCache = atspi.Accessible._cache.copy()
+
+        print "dumpMemoryStats-----------------END---------------------"
+
     def textAttrsToDictionary(self, str):
         """Converts a string of text attribute tokens of the form
         <key>:<value>; into a dictionary of keys and values.
Index: src/orca/focus_tracking_presenter.py
===================================================================
--- src/orca/focus_tracking_presenter.py	(revision 2453)
+++ src/orca/focus_tracking_presenter.py	(working copy)
@@ -294,6 +294,25 @@
         except:
             pass 
 
+    def _cleanupCache(self):
+        """Looks for defunct accessible objects in the cache and removes them.
+        """
+
+        print "_cleanupCache called."
+        objectsRemoved = 0
+        for obj in atspi.Accessible._cache.values():
+            try:
+                if obj.state.count(atspi.Accessibility.STATE_DEFUNCT):
+                    atspi.Accessible.deleteAccessible(obj)
+                    objectsRemoved += 1
+            except CORBA.COMM_FAILURE:
+                print "_cleanupCache: got COMM_FAILURE."
+                atspi.Accessible.deleteAccessible(obj)
+                objectsRemoved += 1
+
+        debug.println(debug.LEVEL_OFF,
+                      "_cleanupCache: %d objects removed." % objectsRemoved)
+
     def _reclaimScripts(self):
         """Compares the list of known scripts to the list of known apps,
         deleting any scripts as necessary.
@@ -461,6 +480,7 @@
             if event.source == atspi.Accessible.makeAccessible(
                                    self.registry.desktop):
                 self._reclaimScripts()
+                self._cleanupCache()
                 #import gc
                 #gc.collect()
                 #print "In process, garbage:", gc.garbage
