mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-25 04:32:33 -06:00
113 lines
4.9 KiB
Python
113 lines
4.9 KiB
Python
from direct.directnotify.DirectNotifyGlobal import directNotify
|
|
from direct.showbase.DirectObject import DirectObject
|
|
from direct.showbase.Job import Job
|
|
import gc, __builtin__
|
|
|
|
class MessengerLeakObject(DirectObject):
|
|
def __init__(self):
|
|
self.accept('leakEvent', self._handleEvent)
|
|
def _handleEvent(self):
|
|
pass
|
|
|
|
def _leakMessengerObject():
|
|
leakObject = MessengerLeakObject()
|
|
|
|
class MessengerLeakDetector(Job):
|
|
# check for objects that are only referenced by the messenger
|
|
# and would otherwise be garbage collected
|
|
notify = directNotify.newCategory("MessengerLeakDetector")
|
|
|
|
def __init__(self, name):
|
|
Job.__init__(self, name)
|
|
self.setPriority(Job.Priorities.Normal*2)
|
|
jobMgr.add(self)
|
|
|
|
def run(self):
|
|
# set of ids of objects that we know are always attached to builtin;
|
|
# if an object is attached to one of these, it's attached to builtin
|
|
# this cuts down on the amount of searching that needs to be done
|
|
builtinIds = set()
|
|
builtinIds.add(id(__builtin__.__dict__))
|
|
try:
|
|
builtinIds.add(id(base))
|
|
builtinIds.add(id(base.cr))
|
|
builtinIds.add(id(base.cr.doId2do))
|
|
except:
|
|
pass
|
|
try:
|
|
builtinIds.add(id(simbase))
|
|
builtinIds.add(id(simbase.air))
|
|
builtinIds.add(id(simbase.air.doId2do))
|
|
except:
|
|
pass
|
|
try:
|
|
builtinIds.add(id(uber))
|
|
builtinIds.add(id(uber.air))
|
|
builtinIds.add(id(uber.air.doId2do))
|
|
except:
|
|
pass
|
|
|
|
while True:
|
|
yield None
|
|
objects = messenger._Messenger__objectEvents.keys()
|
|
assert self.notify.debug('%s objects in the messenger' % len(objects))
|
|
for object in objects:
|
|
yield None
|
|
assert self.notify.debug('---> new object: %s' % itype(object))
|
|
# try to find a path to builtin that doesn't involve the messenger
|
|
# lists of objects for breadth-first search
|
|
# iterate through one list while populating other list
|
|
objList1 = []
|
|
objList2 = []
|
|
curObjList = objList1
|
|
nextObjList = objList2
|
|
visitedObjIds = set()
|
|
|
|
# add the id of the object, and the messenger containers so that
|
|
# the search for builtin will stop at the messenger; we're looking
|
|
# for any path to builtin that don't involve the messenger
|
|
visitedObjIds.add(id(object))
|
|
visitedObjIds.add(id(messenger._Messenger__objectEvents))
|
|
visitedObjIds.add(id(messenger._Messenger__callbacks))
|
|
|
|
nextObjList.append(object)
|
|
foundBuiltin = False
|
|
|
|
# breadth-first search, go until you run out of new objects or you find __builtin__
|
|
while len(nextObjList):
|
|
if foundBuiltin:
|
|
break
|
|
# swap the lists, prepare for the next pass
|
|
curObjList = nextObjList
|
|
nextObjList = []
|
|
assert self.notify.debug('next search iteration, num objects: %s' % len(curObjList))
|
|
for curObj in curObjList:
|
|
if foundBuiltin:
|
|
break
|
|
yield None
|
|
referrers = gc.get_referrers(curObj)
|
|
assert self.notify.debug('curObj: %s @ %s, %s referrers, repr=%s' % (
|
|
itype(curObj), hex(id(curObj)), len(referrers), fastRepr(curObj, maxLen=2)))
|
|
for referrer in referrers:
|
|
#assert self.notify.debug('referrer: %s' % itype(curObj))
|
|
yield None
|
|
refId = id(referrer)
|
|
# don't go in a loop
|
|
if refId in visitedObjIds:
|
|
#assert self.notify.debug('already visited')
|
|
continue
|
|
# don't self-reference
|
|
if referrer is curObjList or referrer is nextObjList:
|
|
continue
|
|
if refId in builtinIds:
|
|
# not a leak, there is a path to builtin that does not involve the messenger
|
|
#assert self.notify.debug('object has another path to __builtin__, it\'s not a messenger leak')
|
|
foundBuiltin = True
|
|
break
|
|
else:
|
|
visitedObjIds.add(refId)
|
|
nextObjList.append(referrer)
|
|
|
|
if not foundBuiltin:
|
|
self.notify.warning(
|
|
'%s is referenced only by the messenger' % (itype(object)))
|