Title: ctypes array types create reference cycles
Type: Stage:
Components: ctypes Versions: Python 3.5
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Eric.Wieser, amaury.forgeotdarc, belopolsky, josh.r, meador.inge
Priority: normal Keywords:

Created on 2018-04-12 08:45 by Eric.Wieser, last changed 2018-04-12 22:23 by josh.r.

Messages (3)
msg315216 - (view) Author: Eric Wieser (Eric.Wieser) * Date: 2018-04-12 08:45
Discovered in

A reproduction:
In [1]: import ctypes

In [2]: def make_array_ctype(shape):
   ...:     import ctypes
   ...:     ct = ctypes.c_uint8
   ...:     for i in shape:
   ...:         ct = i * ct
   ...:     return ct

# all on one line to keep ipython out of this
In [3]: gc.collect(); x = make_array_ctype((1,)); del x; gc.collect()

Using the proposed function in, we get a few more details:
In [4]: from numpy.testing import assert_no_gc_cycles

In [5]: assert_no_gc_cycles(make_array_ctype, (1,))
AssertionError: Reference cycles were found when calling make_array_ctype: 7 objects were collected, of which 6 are shown below:
  tuple object with id=2822255556536:
    (<class '_ctypes.Array'>,)
  PyCArrayType object with id=2822226500408:
    <class '__main__.c_ubyte_Array_1'>
  getset_descriptor object with id=2822252062256:
    <attribute '__dict__' of 'c_ubyte_Array_1' objects>
  getset_descriptor object with id=2822252062184:
    <attribute '__weakref__' of 'c_ubyte_Array_1' objects>
  tuple object with id=2822243712440:
    (<class '__main__.c_ubyte_Array_1'>,
     <class '_ctypes.Array'>,
     <class '_ctypes._CData'>,
     <class 'object'>)
  StgDict object with id=2822226211928:
    {'__dict__': <attribute '__dict__' of 'c_ubyte_Array_1' objects>,
     '__doc__': None,
     '__module__': '__main__',
     '__weakref__': <attribute '__weakref__' of 'c_ubyte_Array_1' objects>,
     '_length_': 1,
     '_type_': <class 'ctypes.c_ubyte'>}

I suppose this isn't really a bug, but it's not clear to me why a cycle needs to be created here.
msg315217 - (view) Author: Eric Wieser (Eric.Wieser) * Date: 2018-04-12 08:47
Apologies, I missed the important part of that snippet:
In [3]: gc.collect(); x = make_array_ctype((1,)); del x; gc.collect()
Out[3]: 7
msg315236 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2018-04-12 22:23
Pretty sure this is a problem with classes in general; classes are self-referencing, and using multiplication to create new ctypes array types is creating new classes.
Date User Action Args
2018-04-12 22:23:40josh.rsetnosy: + josh.r
messages: + msg315236
2018-04-12 16:27:31ned.deilysetnosy: + amaury.forgeotdarc, belopolsky, meador.inge
2018-04-12 08:47:39Eric.Wiesersetmessages: + msg315217
2018-04-12 08:45:09Eric.Wiesercreate