Repository: nvaccess/nvda

Issue:
Over time, NVDA lags with firefox open
**Reported by tspivey on 2013-04-07 16:21**
If I leave firefox open for a long time (can be hours to days), NVDA starts to respond slowly. I notice while alt+tabbing and moving around lists in tween.
When I restart firefox, this stops for another few hours.



Discussion:
Comment 1 by briang1 on 2013-04-08 07:07
Well the problem I find that causes this is dependent on which update channel you are on. since the  increase in betas etc, I've found that while its downloading in the background then Firefox can get very sluggish, but as a restart installs the new code it speeds up again. Is this what you are seeing? You can test if its downloading by going to help, about and moving to the very top where it will tell you the version and any activity like downloading update or installing update.

Comment 2 by jteh on 2013-04-09 07:03
Quick technical notes:
- Probably caused by treeInterceptorHandler.cleanup, which is called for every focus change. isAlive does cross-process calls and this is O(n) based on the number of buffers. It might also respond slowly if the application is busy.
- If we can, it'd be ideal to not call cleanup on every focus change and instead do it when the user is idle or similar.
- This needs to be considered carefully, as it might break things; we don't want new objects being associated with the wrong buffers, etc. In particular, consider 687463144883db028a4657842b541f1af3a9ac3c.

Comment 4 by tspivey on 2013-04-21 06:15
I haven't been tracking this all that frequently, but it usually takes around 30-40 MS to call cleanup.
I notice this. Not all the time, but enough to where I don't want to have a lot of tabs open, because it negatively impacts the rest of my system.
In firefox, it seems to take around 3 ms per tab. I'm testing this by creating new tabs at my homepage, which is about:blank.

Timing script:

```
    def script_test(self, gesture):
        total=0
        for i in xrange(10):
            t1=time.time()
            treeInterceptorHandler.cleanup()
            t2 = (time.time()-t1)*1000
            total += t2
        ui.message("%d" % (total/10))
```

We can probably improve this significantly by cleaning up the isAlive property on the gecko_ia2 vbuf. Right now, it calls `NVDAObjects.IAccessible.getNVDAObjectFromEvent`, which is a complete waste. As a minimum, we could just check for the defunct state. Even calling `accChild` directly would be better than calling `NVDAObjectFromEvent`.

P2 because this can make NVDA sluggish for users with a lot of tabs.

Resolving patch:
diff --git a/source/virtualBuffers/gecko_ia2.py b/source/virtualBuffers/gecko_ia2.py
--- a/source/virtualBuffers/gecko_ia2.py
+++ b/source/virtualBuffers/gecko_ia2.py
@@ -119,14 +119,15 @@ def _get_isAlive(self):
 		root=self.rootNVDAObject
 		if not root:
 			return False
-		if not winUser.isWindow(root.windowHandle) or controlTypes.STATE_DEFUNCT in root.states:
+		if not winUser.isWindow(root.windowHandle):
 			return False
 		try:
-			if not NVDAObjects.IAccessible.getNVDAObjectFromEvent(root.windowHandle,winUser.OBJID_CLIENT,root.IA2UniqueID):
-				return False
-		except:
-			return False
-		return True
+			isDefunct=bool(root.IAccessibleObject.states&IAccessibleHandler.IA2_STATE_DEFUNCT)
+		except COMError:
+			# If IAccessible2 states can not be fetched at all, defunct should be assumed as the object has clearly been disconnected or is dead
+			isDefunct=True
+		return not isDefunct
+
 
 	def getNVDAObjectFromIdentifier(self, docHandle, ID):
 		return NVDAObjects.IAccessible.getNVDAObjectFromEvent(docHandle, winUser.OBJID_CLIENT, ID)


Test patch: