Changes between Version 6 and Version 7 of NumPyRefactoring

Show
Ignore:
Timestamp:
08/31/10 11:11:10 (3 years ago)
Author:
jasonmccampbell
Comment:

Started garbage collected example

Legend:

Unmodified
Added
Removed
Modified
  • NumPyRefactoring

    v6 v7  
    6868 
    6969=== Reference-counted Interface Example === 
     70This example walks through an example of the handshaking between core and interface layer objects when the interface uses reference-counted memory management.  Where code is show it uses the CPython interface layer as an example but the concepts are generally applicable for other reference-counted systems. 
     71 
    7072When the core library constructs a new !NpyArray instance, '''A''', a callback is made to the array wrapper callback provided by the interface (`!NpyInterface_ArrayNewWrapper` in ctors.c for the CPython interace). This function returns an wrapper object (`!PyArrayObject` for the CPython interface), '''Awrap'''.  At this point we have: 
    7173{{{ 
     
    107109 
    108110=== Garbage-collected Interface Example === 
    109 This example walks through an example of the reference count handshaking between the core and the IronPython interface & garbage collector. 
     111'''NOTE: This example is under construction and currently incomplete and probably incorrect in places.''' 
     112 
     113This example is similar to the reference counted example above but shows how the memory management system works with a garbage collected environment.  The examples used apply to IronPython and the C#/.NET environment but should be generally applicable to other garbage collected systems. 
     114 
     115When the core library constructs a new !NpyArray instance, '''A''', a callback is made to the array wrapper callback provided by the interface (`!NpyArray.ArrayNewWrapper` in NpyArray.cs for the IronPython interace). This function returns an IntPtr to a GCHandle instance that references the wrapper object (`ndarray` for the IronPython interface), '''Awrap'''.  At this point we have: 
     116{{{ 
     117A->nob_refcnt = 1 
     118A->nob_interface = GCHandle(Awrap) 
     119}}} 
     120 
     121'''A''' has a reference count of '1' and holds a GC reference to the wrapper instance.   
     122 
     123Now suppose '''A''' is returned from the core to the interface layer.  The interface layer can convert '''A''' to '''Awrap''' by calling `NpyArray.ToInterface<ndarray>(A)`.  This causes the reference to be moved from the core to the interface layer: 
     124{{{ 
     125ndarray *Awrap; 
     126IntPtr *A = someFunctionReturningNpyArray(); 
     127 
     128Awrap = NpyArray.ToInterface(A); 
     129NpyArray.Decref(A); 
     130}}} 
     131 
     132The call to `ToInterface` accesses the `nob_interface` field of '''A''' to retrieve the `GCHandle` referencing '''Awrap''' and returns the ''''Awrap''' instance.  Calling `NpyArray.Decref` results in the reference count of '''A''' going from 1 to 0, and thus '''A''' releases it's reference to '''Awrap'''.  Releasing the reference in this environment means that the `GCHandle` instance pointed to by `A->nob_interface` is deallocated.  This would break the link to '''Awrap''' so a new weak reference is allocated: 
     133{{{ 
     134GCHandle old = A.nob_interface; 
     135A.nob_interface = GCHandle.Alloc(old.Target, GCHandleType.Weak); 
     136old.Free(); 
     137}}} 
     138 
     139At this point, if the interface code stops referencing '''Awrap''', the garbage collector will be free to deallocate it since the '''A''' only holds a weak reference.  In this case, the finalizer for '''Awrap''' will dealloc '''A''' as well. 
     140 
     141Instead, consider the case where '''A''' is retrieved from '''Awrap'''.  In the IronPython interface this is done using the `Array` property: 
     142{{{ 
     143ndarray Awrap; 
     144IntPtr A; 
     145 
     146A = Awrap.Array; 
     147NpyArray.Incref(A); 
     148}}} 
     149 
     150The call to `!NpyArray.IncRef` causes the reference count on '''A''' to go from 0 to 1 and thus it must hold a reference to '''Awrap'''.  This is done by deallocating the weak reference in `nob_interface` and replacing it with a newly allocated full reference.  For example: 
     151{{{ 
     152GCHandle oldWeak = A.nob_interface; 
     153A.nob_interface = GCHandle.Alloc(oldWeak.Target); 
     154oldWeak.Free(); 
     155}}} 
     156 
     157At this point, if the interface stops referencing '''Awrap''' then there is one reference on '''A''' and '''A''' holds the the only GC reference to '''Awrap'''.  If the core calls `Npy_DECREF` on '''A''', the reference count will go to zero and the GCHandle to '''Awrap''' will also be deallocated.  Since neither instance is now references, the garbage collector will at some point collect '''Awrap''' and the finalizer for '''Awrap''' will deallocate '''A'''. 
    110158 
    111159== Object Creation ==