Foreign Function Interface: JNI
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
the native interface to communicate with the host operating system. The orig
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
languages have been re
written to follow the JNI standard.
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
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
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
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,
try to use already existing code; there is no sense
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,
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
embedded systems; we will examine this possibility later in this paper. Using the
Java Native Interface
will enable programmers to enjoy
languages have to offer
such as execution time.
Java to C
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
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
Comment out the
, 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)
seen on the right side
figure 1.1, save the file as
Compile the Java code with javac jniBubbleSort.java
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
win32 is where
the linker for jni.h and jni_md.h files
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
appear after the
two parameters that are generated from
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,
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
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 “
Without the jvm.dll folder location in the environment
variable path, you will be unable
initialize an instance of the Java V
compile this program as
an executable use
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,
find the class that contains the method to
square our number, sample2.java. 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.
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
the third parameter of
looks like, “(I)I”. For a full list of signature types
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,
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
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
ch which inherit from jObject
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
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
. 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
Get<Type>ArrayRegion, but if the array size is large it may get expensive to make a C copy of
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
(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 4: JNI objects
Figure 5: Code using a global reference
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.
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
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
a part of the Java’s heap because it can be expensive to make a copy of the array in the native
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
, I am not only accessing a private field, I have a
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
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
Now that we have investigated when
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
a large number of developers that are familiar with the language and Java’s
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
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,
s are mostly written in
Java. The Android does use C/C++ for CPU tasks and to drive other peripherals.
Virtual Machine, Dalvik Virtual Machine, is written in C.
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.
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
Sheng Liang (June 1999).
The Java Native Interface Programmer’s Guide and Specification
 Gang Tan; Andrew W. Appel; Srimat Chakradhar; Anand Raghunathan; Srivaths Ravi;
Daniel Wang (2006).
Safe Java Native Interface
Java Programming with JNI
 Dawid Kurzyniec;
Efficient Cooperation between Java and Native
JNI Performance Benchmark
 Demetrius L. Davis.
To JNI or not to JNI?
 Preetham Chandrian (August 2011).
Efficient Java Native Interface for Android based
 Nguyen Thi Thu Trang; Tran Canh Toan; Nguyen Manh Tuan; Takenobu Aoshima
(October 31, 2007).
An experience in developing embedded software using JNI