Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass objects into JNI code in addition to raw pointer value (prevent premature GC) #700

Conversation

matthiasblaesing
Copy link
Member

This is the follow up to the discussion, that happened in #664. This implements the option,
that passes the Pointer/Function object to native in addition to the raw pointer value.

This breaks the JNI layer, but not an outside facing API. Please see the commit message for details.

In addition to the summary in the commit message the raw numbers and benchmarks can be found here:

Raw numbers: http://www.doppel-helix.eu/Pointer_to_Native_Comparison2.ods
Complete material: http://www.doppel-helix.eu/Pointer_to_Native_Comparison2.7z

I added the native parts I could build ad-hoc:

  • Windows x64 + x86 were build on Windows 10 with the 7.1 SDK (emulated on Virtualbox)
  • Linux amd64 was build on my main machine
  • Linux x86 was build in a 32 bit chroot
  • Linux ARM was build in a QEMU emulated machine

I have a plan and done all android builds, but I suggest to evaluate first if #669 should be merged, if so the merge should be done before a full rebuild.

Closes: #664

…premature GC)

The Memory/Pointer object delegates the native calls to static methods
in the Native class. This causes the Memory/Pointer object to become
prematurely eligable for GC for this case:

----------------------------

Memory pointer = <init>;
<do something and work on Memory>
String result = pointer.getWideString(0)
<do nothing more with Memory>

----------------------------

getWideString(0) calls back into the JVM and allocates a new java string.
In this case the GC can become active and collect the Memory object.
After this it is possible to run the finalizer, that in turn frees the
native memory backing the memory object. The native function now
possibly accesses freed memory.

The native code needs to hold references to the relevant object itself,
this is implemented here.

Changes:

API relevant changes:
- Deprecate Native#getDirectByteBuffer(long, long)
  it is functional, but discouraged to be used and should be removed in
  future

JNI-Layer (Native.java + dispatch.c):
- All set<Type> and get<Type>, write and read methods that took a
  pointer address are modified to take a pointer object, the raw pointer
  value and an offset
- All invoke<ReturnType> methods that took a pointer adress (function
  pointer) are modified to take a function object and the raw function
  pointer value

Build-System/Native:
- the jni api version as bumped from 5.0.0 to 5.1.0 (the major version
  was raised in the 4.3.0 development cycle, so not modified)
- all prebuild native libraries were replaced with the "OUT_OF_DATE"
  marker, where no replacement could be build immediately

getDirectByteBuffer(long, long) is the only API relevant method, allother
methods modified are package private and so are not considered API.
getDirectByteBuffer is overloaded with a package private variant
getDirectByteBuffer(Pointer, long, long, long) that reflects the above
described changes.

Executed tests:

- linux-amd64:   all unittests of jna pass
- linux-arm:     1 unittest fails (unload of jnalib, emulated
                 environment (qemu), slow execution leads to timeout)
- linux-x86:     all unittests of jna pass (32bit chroot on 64bit kernel)
- windows-64bit: 2 tests fail (before and after: DirectTypeMapperTest
                 and NativeTest#testSizeOf (bool should be 1, is 4)
- windows-32bit: 2 tests fails (one less that before the change
                 (testLongStringGeneration), other errors see x64)

Performance:

Check was done with JMH - the comparison was between master and the
proposed pointer_native_direct branch:

java -jar benchmarks-master.jar -i 10 -wi 10 -f 5

The benchmarks initialize a Memory block and access it via getInt and
getString, one with an offset of 0 and on with an offset of 5 bytes.

The testmatrix:

              testInt testIntWithOffset testString testStringWithOffset
linux64-jdk7     108%              108%       100%                 101%
linux64-jdk8     107%              108%       100%                 100%
linux32-jdk8      97%               97%       112%                 112%
win32-jdk8        90%               95%        98%                  98%
win64-jdk8        95%               95%        97%                  97%
@matthiasblaesing matthiasblaesing merged commit 66241d1 into java-native-access:master Sep 24, 2016
@matthiasblaesing matthiasblaesing deleted the pointer_native_direct branch September 26, 2016 17:58
mstyura pushed a commit to mstyura/jna that referenced this pull request Sep 9, 2024
Motivation:

Netty 4.1.108.Final was released

Modifications:

Update to latest release

Result:

Depend on latest release
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant