Skip to content

Commit

Permalink
Fix JNIVector garbage collection, check if JVM destroyed (#163)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkitti authored Mar 21, 2022
1 parent 96353a4 commit 880188d
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 5 deletions.
13 changes: 11 additions & 2 deletions src/jniarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,21 @@ for primitive in [:jboolean, :jchar, :jbyte, :jshort, :jint, :jlong, :jfloat, :j
m = quote
function get_elements!(jarr::JNIVector{$primitive})
sz = Int(JNI.GetArrayLength(jarr.ref.ptr))
jarr.arr = unsafe_wrap(Array, $get_elements(jarr.ref.ptr, Ptr{jboolean}(C_NULL)), sz)
# Free the array in release_elements rather than directly via GC
jarr.arr = unsafe_wrap(Array, $get_elements(jarr.ref.ptr, Ptr{jboolean}(C_NULL)), sz; own = false)
jarr
end
JNIVector{$primitive}(sz::Int) = get_elements!(JNIVector{$primitive}($new_array(sz)))
function release_elements(arg::JNIVector{$primitive})
$release_elements(arg.ref.ptr, pointer(arg.arr), jint(0))
# Make sure that JVM has not been destroyed
if JNI.ppenv[1] != C_NULL
arr = arg.arr
ref = arg.ref
# The correct way would be let ccall handle this by removing typing from JNI wrappers
GC.@preserve arg ref arr begin
$release_elements(ref.ptr, pointer(arr), jint(0))
end
end
arg.arr = nothing
end
function convert_result(::Type{JNIVector{$primitive}}, ptr)
Expand Down
9 changes: 6 additions & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,6 @@ end
end

@testset "jni_arrays_1" begin
#=
j_u_arrays = @jimport java.util.Arrays
arr = jint[10,20,30,40,50,60]
jniarr = JNIVector(arr)
Expand All @@ -252,11 +251,13 @@ end
@test "array" == jcall(buf, "toString", JString, ())

# Ensure JNIVectors are garbage collected properly
for i in 1:100000
# This used to be 1:100000
@info "JNIVector GC test..."
for i in 1:1000
a = JNIVector(jchar[j == i ? 0 : 1 for j in 1:10000])
buf = jcall(JCharBuffer, "wrap", JCharBuffer, (JNIVector{jchar},), a)
end
=#
@info "JNIVector GC test complete."
end

@testset "dates_1" begin
Expand Down Expand Up @@ -451,5 +452,7 @@ catch err
sprint(showerror, err, backtrace())
end

# Run GC before we destroy to avoid errors
GC.gc()
# At the end, unload the JVM before exiting
JavaCall.destroy()

0 comments on commit 880188d

Please sign in to comment.