I have many questions about Memory Ownership in Calling C and Fortran Code · The Julia Language.
One example, from this documentation we have:
function sf_bessel_Jn_array(nmin::Integer, nmax::Integer, x::Real)
if nmax < nmin
throw(DomainError())
end
result_array = Vector{Cdouble}(undef, nmax - nmin + 1)
errorcode = ccall(
(:gsl_sf_bessel_Jn_array, :libgsl), # name of C function and library
Cint, # output type
(Cint, Cint, Cdouble, Ref{Cdouble}),# tuple of input types
nmin, nmax, x, result_array # names of Julia variables to pass in
)
if errorcode != 0
error("GSL error code $errorcode")
end
return result_array
end
In this case Ref{Cdouble} is used and none of the unsafe functions are used. The result_array is created in Julia and passed to C thus I don’t have to copy anything.
But, String is used in a very different way in gethostname function:
function gethostname()
hostname = Vector{UInt8}(undef, 128)
ccall((:gethostname, "libc"), Int32,
(Ptr{UInt8}, Csize_t),
hostname, sizeof(hostname))
hostname[end] = 0; # ensure null-termination
return unsafe_string(pointer(hostname))
end
In this case one has to use unsafe_string(pointer(hostname)), but hostname vector was creade in Julia, similar to result_array. Why I have to copy the memory using unsafe function in this case? Maybe this is done just to truncate C string in NUL-terminated. But If I’m using Fortran I should use unsafe_string?
If I change unsafe_string(pointer(hostname)) to String(hostname) I end up with a String with \0 and some trash.
Also, why use Ptr{UInt8} not Ref{UInt8}? Using Ptr{UInt8} for this case will not implicate in memory leak?
After sf_bessel_Jn_array function has the following paragraf:
Note that for this code to work correctly,
result_array
must be declared to be of typeRef{Cdouble}
and notPtr{Cdouble}
. The memory is managed by Julia and theRef
signature alerts Julia’s garbage collector to keep managing the memory forresult_array
while theccall
executes. IfPtr{Cdouble}
were used instead, theccall
may still work, but Julia’s garbage collector would not be aware that the memory declared forresult_array
is being used by the external C function. As a result, the code may produce a memory leak ifresult_array
never gets freed by the garbage collector, or if the garbage collector prematurely freesresult_array
, the C function may end up throwing an invalid memory access exception.