Infrastructure to detect mem leaks in the edit metadata dialog

This commit is contained in:
Kovid Goyal 2010-12-13 17:07:00 -07:00
parent 3a1fd7af56
commit acbbc16bf3
3 changed files with 126 additions and 6 deletions

View File

@ -154,15 +154,17 @@ class EditMetadataAction(InterfaceAction):
d.view_format.connect(lambda
fmt:self.gui.iactions['View'].view_format(row_list[current_row],
fmt))
if d.exec_() != d.Accepted:
d.view_format.disconnect()
ret = d.exec_()
d.break_cycles()
if ret != d.Accepted:
break
d.view_format.disconnect()
changed.add(d.id)
if d.row_delta == 0:
break
current_row += d.row_delta
if changed:
self.gui.library_view.model().refresh_ids(list(changed))
current = self.gui.library_view.currentIndex()

View File

@ -293,6 +293,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
finally:
self.fetch_cover_button.setEnabled(True)
self.unsetCursor()
if self.pi is not None:
self.pi.stop()
@ -442,7 +443,6 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
ResizableDialog.__init__(self, window)
self.cover_fetcher = None
self.bc_box.layout().setAlignment(self.cover, Qt.AlignCenter|Qt.AlignHCenter)
self.cancel_all = False
base = unicode(self.author_sort.toolTip())
self.ok_aus_tooltip = '<p>' + textwrap.fill(base+'<br><br>'+
_(' The green color indicates that the current '
@ -573,7 +573,6 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
QObject.connect(self.series, SIGNAL('editTextChanged(QString)'), self.enable_series_index)
self.series.lineEdit().editingFinished.connect(self.increment_series_index)
self.show()
pm = QPixmap()
if cover:
pm.loadFromData(cover)
@ -593,6 +592,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.original_author = unicode(self.authors.text()).strip()
self.original_title = unicode(self.title.text()).strip()
self.show()
def create_custom_column_editors(self):
w = self.central_widget.widget(1)
layout = w.layout()
@ -907,3 +908,65 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
dynamic.set('metasingle_window_geometry', bytes(self.saveGeometry()))
dynamic.set('metasingle_splitter_state',
bytes(self.splitter.saveState()))
def break_cycles(self):
try:
self.view_format.disconnect()
except:
pass # Fails if view format was never connected
self.view_format = None
self.db = None
self.pi = None
self.cover_data = self.cpixmap = None
if __name__ == '__main__':
from calibre.library import db
from PyQt4.Qt import QApplication
from calibre.utils.mem import memory
import gc
app = QApplication([])
db = db()
# Initialize all Qt Objects once
d = MetadataSingleDialog(None, 4, db)
d.break_cycles()
d.reject()
del d
for i in range(3):
gc.collect()
before = memory()
gc.collect()
d = MetadataSingleDialog(None, 4, db)
d.break_cycles()
d.reject()
del d
for i in range(3):
gc.collect()
print 'Used memory:', memory(before)/1024.**2, 'MB'
gc.collect()
'''
nmap, omap = {}, {}
for x in objects:
omap[id(x)] = x
for x in nobjects:
nmap[id(x)] = x
new_ids = set(nmap.keys()) - set(omap.keys())
print "New ids:", len(new_ids)
for i in new_ids:
o = nmap[i]
if o is objects:
continue
print repr(o)[:1050]
refs = gc.get_referrers(o)
for r in refs:
if r is objects or r is nobjects:
continue
print '\t', r
'''

55
src/calibre/utils/mem.py Normal file
View File

@ -0,0 +1,55 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
## {{{ http://code.activestate.com/recipes/286222/ (r1)
import os
_proc_status = '/proc/%d/status' % os.getpid()
_scale = {'kB': 1024.0, 'mB': 1024.0*1024.0,
'KB': 1024.0, 'MB': 1024.0*1024.0}
def _VmB(VmKey):
'''Private.
'''
global _proc_status, _scale
# get pseudo file /proc/<pid>/status
try:
t = open(_proc_status)
v = t.read()
t.close()
except:
return 0.0 # non-Linux?
# get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
i = v.index(VmKey)
v = v[i:].split(None, 3) # whitespace
if len(v) < 3:
return 0.0 # invalid format?
# convert Vm value to bytes
return float(v[1]) * _scale[v[2]]
def memory(since=0.0):
'''Return memory usage in bytes.
'''
return _VmB('VmSize:') - since
def resident(since=0.0):
'''Return resident memory usage in bytes.
'''
return _VmB('VmRSS:') - since
def stacksize(since=0.0):
'''Return stack size in bytes.
'''
return _VmB('VmStk:') - since
## end of http://code.activestate.com/recipes/286222/ }}}