Re: [pysqlite] unusual memory behavior
Gerhard Häring <[email protected]> Thu, 28 May 2009 09:27:25 +0200
| Newsgroups | gmane.comp.python.db.pysqlite.user |
|---|---|
| Message-ID | <[email protected]> |
Michael Bayer wrote: > This is not necessarily a "bug", but this behavior became apparent > through the SQLAlchemy unit tests. We have a series of tests that > attempt to detect memory leaks by running a block of code repeatedly, > performing a gc.collect() and then comparing the count of objects in > gc.get_objects() over time. We consider a memory leak to be when the > number of objects grows steadily for 30-40 iterations in a row with no > dips. > > So with the latest pysqlite 2.5.5 built statically on an intel mac > against sqlite 3.6.14, we get a steadily growing behavior that grows > for about 250 iterations before dipping back down. It should be pretty much exactly every 200 iterations that object count gets reduced again :-) > Its a little strange and it means we'll eventually have to disable > that test for pysqlite, once the current versions find their way into > the python distribution. The good news is that all SQLalchemy unit > tests besides this one do pass on this pysqlite build. [...] I looked into this and am glad that it's not a bug. Let me explain what happens here. Internally, pysqlite has these objects: connections, cursors and statements. Connections need to have access to all cursors and statements ever created on them. So, the connection object has a *list* of weak references for cursors, and a *list* of weak references for statements. To keep things simple and efficient, this list is only ever appended to. The connection object has also two members created_statements and created_cursors that counts the number of statement and cursor allocations. If created_statements or created_cursors reaches 200, the corresponding list is scanned for weak references that have unreachable objects (i. e. that were del-ed or removed by the gc). The list is then compacted to not contain any NULLs. And the counter member is reset to zero. The two methods are _pysqlite_drop_unused_statement_references and_pysqlite_drop_unused_cursor_references in src/connection.c. -- Gerhard