Foreign Function Interface: JNI

burgerraraΛογισμικό & κατασκευή λογ/κού

18 Νοε 2013 (πριν από 4 χρόνια και 6 μήνες)

85 εμφανίσεις

Foreign Function Interface: JNI

Justin Catterson


Most languages contain a foreign function interface. T
he purpose of this is to reuse libraries that
other languages have already established, access legacy code written in other languages, and to
give programmers the ability to use multiple languages for a program to achieve better
performance. Java is a pre
ferred programming language because it is simple
to write and has a
large library, but performance issues and code that have proven the test of ti
me has prevented
Java from becoming

the language of choice. The Java Native Interface (JNI) was developed
resolve these problems. My paper will discu
ss when the JNI should be used,
some examples that
explain how it works,
problems with the JNI, typical coding errors that may occur while
programming, and possible applications.


Early in the de
velopment stages of Java, it was realized that

would need a way to interface
with native languages. The first release of Java’s Development Kit (JDK 1.0) included a way to
communicate with C and C++. Libraries such as



, and

all used
the native interface to communicate with the host operating system. The orig
inal foreign
function interface did not take into account how different Java Virtual Machines (JVM) handle
memory and different garbage collection schemes. The

Java Native Interface (JNI) was
developed in 1997 with the goal of being compatible across all JVM’s.

Other concerns while
developing the JNI was to be as efficient as possible

to allow the support of time
systems, and allow Java Virtual Machin
e’s to be embedded into native languages.

The JNI has
become the standard for communicating with native interfaces in Java, and

all libraries that

with native

languages have been re
written to follow the JNI standard.

Figure 1

shows where the

JNI fits into the Java Virtual Machine, if Java calls a native functions, JNI calls
the dynamically linked library that contains the native method. If the native application is calling
a library in Java, JNI will allow the native application to create a
Java Virtual Machine.


Figure 1: How JNI communicates with both native apps and the JVM

Determining to
use the

Before deciding you are going to use the JNI, you should first examine your other options.

Using the JNI will add
complexity to your
program; it will make your program more difficult to
debug, you will also have to consider memory leaks
, you will be more vulnerable to security
, and it can be expensive to make the call through JNI

If you decide to use JNI, you will
lose one of J
ava’s advantages, being portable

all code that is implemented in a native language
will not be portable and will have to be re
written to support other operating systems. F
or all
these reasons, it is obvious you should first review your other options
before investing the effort
into developing a solution throu
gh the JNI.
One way to get around using the

is through data
communication, such as a TCP/IP connection.
In this case, the programmer will need to set
up a
server type system, and the
server will need to determine how to interoperate the data.
Using a TCP/IP connection does come with its own risks, but this is out of scope for this paper.

Another possible solution is to use a JDBC (Java Database Connectivity)

this solution simply
ects Java to a database. The native application would need also to connect to the database,
and the two programs would communicate information through the databa
se. One risk you run
with using a database is cost, if the database is not designed properly,

maintaining the system
may become expensive.
Another alternative to using the JNI is by using distributed object
technology such as the Java IDL API.

An IDL (Interface Definition Language) can be used to
find objects, call methods, and get returned data

while on a remote system,


Although there are added complexities in using the Java Native Interface, there are some
acceptable reasons for deciding to use it.
All of the alternatives expect that the nati
ve part of the
and the J
ava part of the program can exist on separate processes, and sometimes on a
different computer entirely. All of the cases in which it is acceptable to use the JNI, the native
code and the Java code exist on the same process. Separating the progr
am into processes may
cause a “memory footprint” which may be problematic. It takes less memory to load a native
library than to start a new process.

an application will need to use a feature that is

supported in the

if such a case


the JNI may be the only solution. It is also
accepted to use the JNI when you want to access an existing library from a native language. In
the field of software engineering,
want to
try to use already existing code; there is no sense
in re
nventing the wheel
. Code that has been

should be used rather than
risking creating new
code that has not been tested
site or in the field in which the code will be


Java’s design concentrated on reliability, for example,
ava en
sures that the



are within range. Java’s concern of reliability did come with a tradeoff, the cost of
execution time. Typically, when dealing with real
time embedded systems

we have to deal with
critical sections. Because Java typ
ically cannot execute as fast as some native languages
such as C, Java does not get considered as a possible solution for embedded systems or in any
situations where time is the primary concern
. With the JNI, Java could be used as a possible
solution for
embedded systems; we will examine this possibility later in this paper. Using the
Java Native Interface

will enable programmers to enjoy
some of
the advantages
that other
languages have to offer

such as execution time.

Java to C


To fully
understand how the JNI works and how it could possibly be used

we must run through
some tutorials. In this section, I will instruct you how
use the Java Native Interface to call a
native function through Java.

My tutorial was executed using the Windo
ws 7 operating system,
Java Development Kit (JDK) version 1.6_20 and a copy of Microsoft Visual Studio 2010.
Although my tutorial was executed with Windows OS, JDK 1.6_20, and Visual Studio 2010, you
do not need
to do
same. You will need at least JDK

1.2 and some way to compile the C++
code into a DLL.

This program will read in a file from myfile.txt that I do not provide, just make


should include a list of numbers less than 10 digits with each number separated
by one
new line
character feed.

Comment out the
call to


, this was used to
demonstrate a crash


Add to your system variable path the location of your JDK bin folder. In my case,
Program Files (x86)


Write the
Java class


seen on the right side

figure 1.1, save the file as


Compile the Java code with javac


Create the header file for C++ with javah jniBubbleSort


Write the native C++ code seen in figure 1.1, save the file as jniBubbl


Execute the vcvarsall.bat in the vc directory of Visual Studio


Compile the native file into a dll using
using cl


. The

Iinclude and

win32 is where
the linker for jni.h and jni_md.h files

respectively. The

MD links the
jniBubbleSort.dll with the Win32 multithreaded C library.


Now you should be able to execute the program using java jniBubbleSort


Figure 2: Java to C++
using the JNI

From the C++ code, you might be wondering what the extra parameters, JNIEnv * and the
jobject are for. The JNIEnv pointer points to the list of JNI functions that are available for the
C++ code to use. The JNIEnv can be used to access Java

classes, methods, and fields

that are a
part of the Java Virtual Machine,

but it is not used in this tutorial. In a later tutorial I will be
using the JNIEnv to access a field in a Java class. For a list of JNI functions please visit
. The jobject field
a reference to the Java object in which the native method belongs to.

You can think of the
jobject field passed as the reserved word ‘this’ in C++.

If any parameters were intended to be
passed, they

appear after the

two parameters that are generated from

the JNI.

Earlier in this paper,
se the JNI


it was stated that it is acceptable to use the

to use libraries previously written. In order to use previously used libraries, you will need to
make a wrapper class due to the code generated by the JNI. To use a library previously written,
create a
Java class that will contain all the functions in the legacy library. For each native
method created, you will then be able to call the native function you desire and return any data

C++ to Java: Embedding a JVM Tutorial

As shown in figure 1.0, the JNI may also be used to embed a Java Virtual Machine within a
native application.
In order to embed a JVM into a native application, you must add to the

system path environment variable
the file location of where the JVM.dll

exists. In my case I
found the jvm.dll file in the folder location “
Program Files
Without the jvm.dll folder location in the environment
variable path, you will be unable
initialize an instance of the Java V
irtual Machine.
compile this program as
an executable use
MD Sample2.cpp
link "C:

Program Fil
es (x86)
In this tutorial
created by IBM developerWorks, we will create a JVM an
d call a Java method to square the
number 5. We will first create the JVM,
and then

find the class that contains the method to
square our number, To find the Java class, we will use FindClass(“sample2”).
After finding the Java class we wil
l find the
Method ID of the static method intMethod.
To find
the static method’s Method ID we use getStaticMethodID passing three parameters

Figure 3: C++ to Java using the JNI


the Java class that was found using Find


he name of the method we


trying to find, intMethod


astly a string to represent the signature of the parameter that will be passed into the
method and the return type



, there is only one parameter, an integer,

the method also returns an
integer, so
the third parameter of


looks like, “(I)I”. For a full list of signature types
please visit

In this example, most of the code is for initializ
ing the Java Virtual Machine. My tutorial has the C code
and the Java code in separate directories, so I must set an option to point to the Sample2.class directory,

Mapping Types


Because Java and native languages such as C treat types differently, we must investigate how the
Java Native Interface maps types. For example, Java treats arrays as objects and

C treats arrays

pointers to memory locations. In the JNI, it treats types as either

a primitive type or a
reference type. Primitive types are defined as a specific number of bits

and are either signed or
unsigned. An example of a primitive type is a char. A character in Java is an unsigned 16
Unicode character.

The Java character is mapped to an unsig
ned short in C called a jchar. In
most cases, you can treat the jchar as
char in C
, but note that the character set in Java can be
twice as large as the ASCII table supported in C (8 bits)

Reference types include everything that
does not have a pre
fined bit size. The JNI splits reference types into a few
different class
ch which inherit from jObject

see figure

When using Java reference types, you cannot use
the same syntax as you would if the type was native to C. For example, you cannot use
myClass.doIt() to call the objects myClass’s doIt method. If you woul
d like to call myClass’s
doIt method
you must find the class of the o
bject and the method id to call the method using the
JNI functions. In a later tutorial I will be showing this.

There is also added syntax for accessing
arrays. To access elements of a

Java array, you must
copy over the elements
of the array
into a C array

or retrieve a pointer to which the Java
array exists
. If the array size is small or you
only want a small section of an array, it is typical to copy the elements into a C
array with
Get<Type>ArrayRegion, but if the array size is large it may get expensive to make a C copy of
the array.

Within the different

of references, they categorize these objects by how they

removed from the virtual machi

There are local references, global referen
ces, and weak
global references. Local references are objects that have been new’d by a native method and
only exist during the execution of the native met
hod. Local references are common because
there is no
thing that needs to be done to specify that the object is a local reference. If you want
to make an object C static within a method, meaning there is only one refere
nce that exists to the
object within memory, you should not use

a local reference. If a static object is declared local, it
will not exist after the execution of the native method, and later calls to the native method could
cause memory corruption or could cause the program to crash.

To allow the C program to
e objects static, the programmer must
use newGlobalRef or newWeakGlobalRef

see figure

(code taken from

on the declarations
Global references exist

until the programmer
fies to delete

the object using DeleteGlobalRef.

Weak references do not ne
ed to be
specified to be deleted from memory, they can be garbage collected, but they may also be deleted
by the programmer using

Figure 1.2


Figure 4: JNI objects

Figure 5: Code using a global reference

JNI Issues

As stated in
“Determining to use the JNI”, there are many issues that are related to using the JNI.
In this section we will investigate the security problem
, memory management issues, and

out the overhead cost of using the Java Native Interface.

By u
sing the J
NI, it becomes very easy
to read/write to data is Java you should not be able to. Because of the JNIEnv pointer, you have
access to all classes and fields. So long as the native language knows about a class, it will be
able to read/write to
private field

and overwrite the values of constants.

See figure 1.4 for code
I wrote that exposes this issue

and many other issues
. This is not the only problem related to
native languages accessing memory in Java’s heap. Typically for accessing large arrays

that are
a part of the Java’s heap because it can be expensive to make a copy of the array in the native
language, you
get a pointer to the array instead. With a pointer to the array, it is easy to go
outside the bounds of the array and accidently read/o
verwrite data in Java’s heap not part of the


When using the JNI, you will be responsible for memory management on the native
language side. Although in C, this is nothing new, you will need to mange memory for the Java
Virtual Machine. In my exam
ple, figure
, I am not only accessing a private field, I have a
memory leak.

The memory leak exists because my call getStringUTFChars does not have a
corresponding releaseStringUTFChars. Be very

about all JNI calls you make and
ensure that you

do not need to make a corresponding call to release memory.

This example is
also missing error checks. For every call from the native language to Java, you will need to
check that errors have not occurred because the native language will not throw the e




are using error checking

for finding the classes and finding the method id’s. In

, it probably should check that square has a value.

Returning reference types from native
languages can also cause problems. Let’s say yo
u wanted to return an UnsafePerson seen in
example 1.4 in a native function. The return type for this native function would be a jObject, so
it would be really easy to return a different jObject

than what the Java code was expecting.

Figure 6: JNI
coding issue example

In order to determine whether or not making use of the JNI for ti
me critical situations, we
investigate how much time it takes to make a call through the Java Native Interface.

L. Davis wrote bench
mark tests for two
algorithms, heap sort and Discrete Fast Fourier
. The tests he ran were not optimized so these programs are not testing how good the
optimization is for the compilers. In his research he runs his tests with different array sizes to
check the imp
act of array sizes on Java and on C++. He also runs a number of iterations to
determine how expensive it is to make the call through the JNI.

The results are shown

graphs on figure

separated by array size.

This graph demonstrates, for this ca
se it is worth
making the call through the JNI to execute the C++ algorithm rather than executing the
equivalent Java implementation. The far right graph on figure

shows a large performance hit
for the JNI implementation, but this is not caused from


expense of the JNI. The author states
that this graph most likely is due to memory limitations on the computer used for testing.
e statistical data test visit [4
. These


will be better at determining how much


will cost for
different JNI operations and on different Just
Time compilers. For most JNI
operations, it takes a couple hundred nanoseconds, so typically it is fairly negligible.

Figure 7: JNI execution time vs

pure Java execution time

JNI Applications

Now that we have investigated when
we should

use the JNI and understand how
some of the
problems that can occur
, we can begin to look into
where it would be applicable to use the Java
Native Interface in industry.

C and assembly languages dominate the ma
rket for small
embedded systems because of its efficiency and its ease to communicate with other languages.
As embedded projects become larger and more complex, it becomes more difficult to maintain
and to develop. Java has become more attractive for dev
eloping large embedded projects
because there

a large number of developers that are familiar with the language and Java’s
large library

it easier to develop than C/C++.

With the help of the JNI, Java could be use
to write the “upper stream” [7

and have the C code control the devices.

With Java being
independent from the host platform, the Java software could be reused on different systems,
reducing the cost of

the software on
different machines.

The Android phones follow this exact
development scheme. Applications such as contacts, e
mail, browser settings, and all applications that come with the Android package are written in
Java. Other programs that manage resources,
such as
voice application
s are mostly written in
Java. The Android does use C/C++ for CPU tasks and to drive other peripherals.

Even Androids
Virtual Machine, Dalvik Virtual Machine, is written in C.


Design Conclusions

This paper has shown you when it is acceptable to use the

Java Native Interface. Once it has
been decided to use the JNI, you must try to avoid some of the issues related. Designing a good
system will also help prevent some of the issues that may happen such as memory leaks and
the overhead of the JNI min
imal. Try to keep the control flow simple, code that goes back and
forth between the JVM and native code, is probably designed
. Every time you make
calls back and forth you are wasting time. Keep the native code to a minimum, by doing this y
will prevent memory leaks that could occur, and your code will be less complex. Separate your
Java code from your native code.
Native code is platform dependent, by separating the Java
code from the native code; you will have a porting layer.

A poss
ible application for the JNI is
for large embedded projects. Keep the microcontrollers written in C and have the “upper
stream” such as applications within the embedded system written in Java. If you are interested in
learning more about embedded develo
pment using the JNI, I would suggest
starting with
Android development.


Sheng Liang (June 1999).
The Java Native Interface Programmer’s Guide and Specification

Retrieved from

[2] Gang Tan; Andrew W. Appel; Srimat Chakradhar; Anand Raghunathan; Srivaths Ravi;
Daniel Wang (2006).
Safe Java Native Interface

Retrieved from

[3] Scott
Stricker(March 2002).
Java Programming with JNI

Retrieved from

[4] Dawid Kurzyniec;
Vaidy Sunderam.
Efficient Cooperation between Java and Native


JNI Performance Benchmark

Retrieved from

[5] Demetrius L. Davis.
To JNI or not to JNI?

Retrieved from

[6] Preetham Chandrian (August 2011).
Efficient Java Native Interface for Android based
Mobile Devices.

Retrieved from

[7] Nguyen Thi Thu Trang; Tran Canh Toan; Nguyen Manh Tuan; Takenobu Aoshima

(October 31, 2007).
An experience in developing embedded software using JNI

Retrieved from