I don't quite understand how reference counting is done with memoryviews in large/longer nogil sections. Let's assume basically all my code is nogil, except for the creation of a numpy-array-to-memoryview deep down. The memoryview is returned and used upwards.
A fairly simple example would be
import numpy as np
cdef:
double[::1] mv
cdef double[::1] someFun(int nn) nogil:
cdef:
double[::1] mvb
with gil:
mvb = np.arange(nn, dtype=np.double)
return mvb
with nogil:
mv = someFun(30)
# Here could be MUCH more "nogil" code
# How is memory management/reference counting done here?
I assume when someFun() returns the memoryview the refcount of the numpy array should still be at 1. How does Cython handle the refcounting afterwards? I mean it's not allowed to change the refcount even if the memoryview/array is dereferenced, right? And how would it know to dereference the memoryview if there were several layers with nogil code above, and maybe unlike to someFun() the memoryview isn't returned upwards?
EDIT: So I figured out a rather crude way to do some more testing. My code now looks like this.
import numpy as np
cdef extern from "stdio.h":
int getchar() nogil
int printf(const char* formatt, ...) nogil
cdef:
double[::1] mv, mv2 = np.ones(3)
int ii, leng = 140000000
cdef double[::1] someFun(int nn) nogil:
cdef:
double[::1] mvb
with gil:
mvb = np.ones(nn, dtype=np.double)
return mvb
with nogil:
mv = someFun(leng)
printf("1st stop")
getchar()
mv = mv2
printf("2nd stop")
getchar()
The interesting part for me is that at the 1st stop the array/memoryview mv
is still allocated, but when I dereference it gets free'd until 2nd stop. I only checked memory usage with htop
(that's why the array is chosen so large), there is probably a better way.
Obviously that free/refcounting behavior what I want to happen, but it's weird that it does it when it doesn't have the GIL. Maybe memoryviews are not completely nogil?
Can someone explain to if this is reliable behavior?