[ZCM] [ZC] 2324/ 2 Comment "Memory leak in Shared.DC.ZRDB.Results.SQLAlias"

"Collector: Zope Bugs, Features, and Patches ..." <[email protected]> Wed, 16 May 2007 13:18:01 -0400
Newsgroups gmane.comp.web.zope.devel.collector-monitor
Message-ID <[email protected]>
Issue #2324 Update (Comment) "Memory leak in Shared.DC.ZRDB.Results.SQLAlias"
 Status Pending, Zope/bug medium
To followup, visit:
  http://www.zope.org/Collectors/Zope/2324

==============================================================
= Comment - Entry #2 by tseaver on May 16, 2007 1:17 pm

I can confirm that this leak is there, and has in fact caused
me to stop using the ZRDB.Results class altogether.  Here is
where the problem arises:

  - For each result set (i.e., each invocation of a SQL method),
    the Results class creates a new class on-the-fly, named 'r'.
    It creates an uppercase and lowercase alias for each column
    in the result set's schema, and sets those aliases as
    attributes of the 'r' class, in order to get their '__of__'
    methods called when the alias is requested as an attribute
    of an instance of 'r'.

  - The cycle is thus betweeen the on-the-fly class, which
    is stashed as the '_class' attribute of the Results instance,
    and the alias(es).  I don't know why that 'r' class is
    unreachable for GC, but it seems to be so.  I also don't
    know how to write a test for the (non)existence of the
    cycle.

My workaround was to move to using a results class which did
not attempt to DWIM the uppercase and lowercase aliases at
all:  the columns can only be accessed using the same spelling
that was used in the original SQL.   BBB will make this harder
to do in the ZRDB.Results module.
________________________________________
= Request - Entry #1 by brunni on May 16, 2007 11:37 am

A leak happens with objects of class Shared.DC.ZRDB.Results.SQLAlias, when
using traversal with a Z SQL Method.

1. Create a Z SQL Method named 'Sql' with one argument named 'my_arg':

      SELECT my_column AS my_column_alias
      FROM my_table
      WHERE my_primary_key = '<dtml-var my_arg sql_quote>'

   check 'Allow "simple" direct traversal' in Advanced.

2. Create a DTML Document named 'Leak':

      <dtml-var my_column_alias>

Then each time calling http://<host>/Sql/1/Leak, one additional Instance of
Shared.DC.ZRDB.Results.SQLAlias (a new str instance with value
'my_column_alias' being referenced by it's attribute _n)
will be created but never again freed unless Zope is restarted.

Notes:

- We used a python 2.4.4 build with Py_TRACE_REFS switched on.
- Cyclic garbage collection is active, but gc.collect() does not free the
  SQLAlias instances. (sys.getrefcount() says 4)

==============================================================