djhenderson / pypyodbc

Automatically exported from code.google.com/p/pypyodbc
0 stars 0 forks source link

Memory leak on Connection and Cursor objects #26

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1.Memory leak, python will not collect unused cursor and connect object.
2. Python 2.7.5, OS: Winows8, pypyodbc version 1.2.0
3. Please see attached py file for testing.

I think the reason of resulting this is the loop in connection.close() method, 
and this object has __del__() method be called. Circular references between 
objects are preventing them from being collected.

below from doc of _del_ function:

http://docs.python.org/2.7/reference/datamodel.html?highlight=__del__#object.__d
el__

Note del x doesn’t directly call x.__del__() — the former decrements the 
reference count for x by one, and the latter is only called when x‘s 
reference count reaches zero. Some common situations that may prevent the 
reference count of an object from going to zero include: circular references 
between objects (e.g., a doubly-linked list or a tree data structure with 
parent and child pointers); a reference to the object on the stack frame of a 
function that caught an exception (the traceback stored in sys.exc_traceback 
keeps the stack frame alive); or a reference to the object on the stack frame 
that raised an unhandled exception in interactive mode (the traceback stored in 
sys.last_traceback keeps the stack frame alive). The first situation can only 
be remedied by explicitly breaking the cycles; the latter two situations can be 
resolved by storing None in sys.exc_traceback or sys.last_traceback. Circular 
references which are garbage are detected when the option cycle detector is 
enabled (it’s on by default), but can only be cleaned up if there are no 
Python-level __del__() methods involved. Refer to the documentation for the gc 
module for more information about how __del__() methods are handled by the 
cycle detector, particularly the description of the garbage value.

Original issue reported on code.google.com by Upd...@gmail.com on 17 Oct 2013 at 11:18

Attachments:

GoogleCodeExporter commented 9 years ago
attaching file

Original comment by Upd...@gmail.com on 17 Oct 2013 at 11:19

Attachments:

GoogleCodeExporter commented 9 years ago
即使直接改用del掉也不可以
---------------------

import pypyodbc, os, gc

def test():
    # if comment the __del__ method in connection and cursor objects, this problem will be solved
    mdb_file = "test.mdb"
    db = pypyodbc.win_create_mdb(mdb_file) if not os.path.isfile(mdb_file) else mdb_file

    #try:
    #    with pypyodbc.win_connect_mdb(mdb_file) as db_con:
    #        cur = db_con.cursor()
    #except pypyodbc.Error, i:
    #    print i.__str__().decode("unicode-escape")
    con = pypyodbc.win_connect_mdb(mdb_file)
    cur = con.cursor()

    del con,cur
print "pypyodbc version %s" % pypyodbc.version
count = 5
while count:
    test()
    print "# --- %d" % count
    print "collected", gc.collect()
    print "garbage count", gc.garbage.__len__()
    print "garbage", gc.garbage
    print "# ---\n"
    count -= 1

----------------
----------------
pypyodbc version 1.2.0
# --- 5
collected 97
garbage count 2
garbage [<pypyodbc.Cursor instance at 0x025FB3C8>, <pypyodbc.Connection 
instance at 0x025F74E0>]
# ---

# --- 4
collected 149
garbage count 4
garbage [<pypyodbc.Cursor instance at 0x025FB3C8>, <pypyodbc.Connection 
instance at 0x025F74E0>, <pypyodbc.Connection instance at 0x025C5B70>, 
<pypyodbc.Cursor instance at 0x0248DF30>]
# ---

# --- 3
collected 149
garbage count 6
garbage [<pypyodbc.Cursor instance at 0x025FB3C8>, <pypyodbc.Connection 
instance at 0x025F74E0>, <pypyodbc.Connection instance at 0x025C5B70>, 
<pypyodbc.Cursor instance at 0x0248DF30>, <pypyodbc.Connection instance at 
0x025C5A30>, <pypyodbc.Cursor instance at 0x025F7850>]
# ---

# --- 2
collected 149
garbage count 8
garbage [<pypyodbc.Cursor instance at 0x025FB3C8>, <pypyodbc.Connection 
instance at 0x025F74E0>, <pypyodbc.Connection instance at 0x025C5B70>, 
<pypyodbc.Cursor instance at 0x0248DF30>, <pypyodbc.Connection instance at 
0x025C5A30>, <pypyodbc.Cursor instance at 0x025F7850>, <pypyodbc.Connection 
instance at 0x025CEC38>, <pypyodbc.Cursor instance at 0x025F76E8>]
# ---

# --- 1
collected 149
garbage count 10
garbage [<pypyodbc.Cursor instance at 0x025FB3C8>, <pypyodbc.Connection 
instance at 0x025F74E0>, <pypyodbc.Connection instance at 0x025C5B70>, 
<pypyodbc.Cursor instance at 0x0248DF30>, <pypyodbc.Connection instance at 
0x025C5A30>, <pypyodbc.Cursor instance at 0x025F7850>, <pypyodbc.Connection 
instance at 0x025CEC38>, <pypyodbc.Cursor instance at 0x025F76E8>, 
<pypyodbc.Connection instance at 0x024BC7B0>, <pypyodbc.Cursor instance at 
0x025F79E0>]
# ---

Original comment by Upd...@gmail.com on 17 Oct 2013 at 11:32

GoogleCodeExporter commented 9 years ago
fixed in version 1.2.1, thanks for reporting

Original comment by jiangwen...@gmail.com on 16 Nov 2013 at 3:43