It is not conceptually clear to me as to when Java uses JNI. The literature 1,2 seems to suggest using JNI is optional - it is a useful feature for my own, existing native C applications, but it is good practice to avoid using it when possible:
Liang indicates "Remember that once an application uses the JNI, it risks losing two benefits [of portability and security]".
However, I was looking at Oracle's API implementation in the SDK, and I see public static native void arraycopy in java/lang/System.java. Questions:
Don't methods marked as such, in native, use JNI?
Doesn't Java make use JNI when making system calls?
System calls are required for any Java API implementation, so if I'm correct, it seems there is no avoiding interfacing with native code.
1: Horstmann, Core Java Volume 2
2. Liang, The Java™ Native Interface Programmer’s Guide and Specification
You list two drawbacks of JNI - portability and security. Actually, there is another one, which is more important in everyday life: JNI calls bear a significant performance cost, because they affect the global JVM state and lock some JVM features, including GC.
As detailed in the other answer, JVM does rely on JNI. But this is not a complete answer.
Your JVM may support fast JNI methods (e.g. Android ART does). These methods are guaranteed to be fast and non-blocking, and they may be performed without state change, see e.g. #FastNative. The Java SDK native methods use such improvements a lot, so they don't suffer the performance costs of conventional JNI.
These native methods do not rely on LoadLibrary() during run. This removes another significant performance cost of JNI - loading and 'binding' the native methods at runtime. The worst risk with runtime binding is that it happens at an arbitrary time, determined by the classloader, and may clash with some other urgent thing that your JVM or app must do at that time. Irrelevant for the system native methods.
Also, portability concerns are irrelevant: the Java runtime is carefully crafted for each supported platform, and in itself it is not 'portable', only the Java apps running on top of it are.
Finally, security risks of JNI are twofold: JNI is not limited by private declarations, and the native code can do dangerous things that compromise any class or app running in the same JVM. And, being loaded from a third-party library, JNI code may be hacked (e.g. it's enough to change OS environment to cause System.loadLibrary() load a fraudster's version of the lib). The system native methods are immune to such attacks.
In the nutshell, even though JVM does use JNI, this is not an excuse to indiscriminately use JNI for your own classes.
Don't methods marked as such, in native, use JNI?
Yes, that's what it means.
Doesn't Java make use JNI when making system calls?
Same question really. Only native methods can call system calls, so Java code can only call system calls via native methods.
Using JNI is optional for applications. It's essential for the JVM.
Related
How does JVM translate API to its implementation inside JVM?
Is it similar to "Linux Kernel syscall" implementation? If so, where are these interfaces? Hope to see the source code.
Figure from https://www.artima.com/insidejvm/ed2/introarch4.html
e.g. ,
Any Java virtual machine implementation must take care to connect these methods of class ClassLoader to the internal class loader subsystem.
https://www.artima.com/insidejvm/ed2/jvmP.html
The API you have linked (https://docs.oracle.com/javase/7/docs/api/), is basically an ordinary class library. When you have installed a JDK, there will be file, src.zip or src.jar, depending on the version, containing the plain Java source code of most of this library. In all versions up to and including Java 8, the compiled API classes are delivered as ordinary jar files, the majority of the API classes being in rt.jar. Starting with Java 9, new module files are used, still, the majority of the API is implemented as ordinary Java code.
You can even browse the source code of certain versions online, e.g. this is the implementation of Object.toString() of version 8, update 40, beta 25, hosted at grepcode.com.
So for most methods, there is nothing “similar to ‘Linux Kernel syscall’” involved when you invoke an API method. It works like an ordinary method invocation and the optimizer may even inline the JRE specific code into your application’s code at runtime. You may also step into the JRE’s code while debugging.
Only a few methods are not implemented as plain Java code, e.g. Object.getClass() is a native method that can only be implemented in a JVM specific way.
There are two general ways to implement these methods. There is a standardized interface, JNI, allowing the interaction of arbitrary native code and Java code. It includes a special linkage between invocations of Java methods declared native and their implementation via JNI. But some methods are handled as intrinsic operations by the JVM instead, which implies that the invocations of these well-known methods (e.g. getClass()) is handled directly by the interpreter/optimizer like a dedicated bytecode instruction. This very efficient handling is sometimes even used for methods, which have an ordinary Java implementation, when there is a platform specific, more efficient alternative. E.g, Integer.rotateLeft and rotateRight have a pure Java implementation, but if the actual CPU used at runtime has dedicated instructions for bitwise rotation, all optimizing JVMs will replace the invocations of these method with intrinsic operations using these CPU instructions.
These day I have been reading about Java Native Interface.So by the way I do have doubt.Let say for a instance,If we need to do a I/O operation in Java program, we exercise the Java API for I/O operations.Moreover,at low level, it should be mapped to OS level I/O handling.The doubt is how Java API interact with native I/O methods in host operating system.
Short and Sweet, I heard some of the methods in JDK are implemented natively.How those native methods are called by Java API.I guess it would be JNI(Java Native Interface).
Could somebody clarify my doubts.
Thanks
Nuwan Arambage
Methods in Java can be marked native to indicate that their implementation is not written in Java or in bytecode, but rather in something platform-dependent. For example, Java I/O operations are almost always implemented as native methods so that they can take advantage of the underlying hardware or OS interface on the machine.
There is no guarantee whatsoever about how native methods are actually implemented. In Sun's (now Oracle's) implementation of the JVM, you can write implementations for native methods by using JNI to define specially-named C functions that interact with custom libraries in order to interface with Java code. However, another JVM could implement native methods in a totally different way. In fact, right now I'm working on a project to implement a JVM in JavaScript, and so all the native methods are implemented in JavaScript rather than C.
In short, there's no "one way" in which native methods are implemented. The whole point is to give maximum flexibility to the JVM and Java library implementations, and so the less specified the behavior is the better.
After a native library has been loaded, the methods are bound (integrated) into the JVM. The Java VM Spec uses the term binding rather then linking to avoid confusion. But that's just wording.
The rest is simple. There are some bytecode operands that are used to invoke a method. And if that message is declared native, then the associated native code is invoked. Parameters and results are converted so that it doesn't make a difference if we call a native or a non-native method.
Have a look at the spec of invokevirtual, the bulleted list covers the native case.
Is there any chance for the the violation of java security policy through java native interface.
Which are the main areas we have to use JNI
Java's Security policies simply do not apply to native code called via JNI, so obviously the native code can violate them at will.
As for what JNI us used for, these days it's mainly to call OS-specific APIs or interface with existing non-Java code. Improving performance used to be a frequently-cited reason, but considering the state of VMs and JIT compilers today, that almost never makes sense.
Yes, once you invoke native code through JNI it can do pretty much anything the current user is allowed to do - e.g. delete all their files. The Java system cannot police anything that native code does.
You don't have to use JNI for anything - it's typically used for e.g. low-level access (e.g. critical error handling for a removable drive) or to access a C API which doesn't have a pure-Java equivalent.
Just out of interest , is it possible to call a C module from a java module ? If so , how to do that ?
yes you can use Java Native Interface to do this:
Yes, you can do it. Whether you should do it is another matter.
On the pro side:
Calling C libraries from Java will avoid the need to recode the libraries in Java (but see below).
For some computational intensive algorithms, a well-written C implementation may be faster than an equivalently well-written Java version.
Some operating system specific operations cannot be implemented in pure Java.
On the con side:
There is a greater overhead in making a JNI call versus a simple Java method call.
If your C library is not thread-safe, you have to be really careful calling it from Java. And as a rule, C libraries are not implemented with thread safety in mind.
If your C library has memory management issues, it may destabilize the Java platform resulting in JVM crashes.
Calling native libraries immediately means that your application is harder to port, and requires a more complicated build process.
Yes, you call C/C++ from Java using the Java Native Interface (JNI) from this purpose.
Java Native Interface: Programmer's Guide and Specification
You can also use SWIG for this purpose:
SWIG Tutorial
Look into JNI (Java Native Interface).
Yes. As others have already mentioned, JNI or Java Native Interface is Sun's preferred way of doing this. If you feel you'll need to call the C code from other languages as well as Java, I'd look into SWIG, which will transparently generate the JNI code for you, but also allow you to do similar things with, for example, Python.
There are a number of C to (Java) bytecode compilers, which may be able to turn your C code into a .jar of portable Java classes you can call directly from Java.
Detriments versus JNI:
There is a noticeable performance penalty, typically at least 100%.
Benefits versus JNI:
Just like running pure Java code, it is safe, does not require special privileges to load, and does not require recompiling for every target platform.
(When I say "JNI" I really mean all Java interfaces to native code. For example, the same applies to CNI.)
Is it possible to call the JVM's built-in native code, i.e. the code that various class in java.lang and java.io call? In other words, can you bypass the built-in java API to access various system-level calls such as file-system access? I know I could do this by building my own native code library and calling that via JNI, but it would be elegant to not need an extra native library for functionality already built into the JVM.
No you can't. It's designed that way on purpose; you would override the API contracts if you could.
In any event, the standard library wrapper code is very slight and with JIT compilers you shouldn't notice any speed impact.
Furthermore, the implementation of those methods are not part of the API spec. What is "native" for one implementation of Java doesn't have to be for another.
You can, of course, use reflection to call the methods providing the code is trusted. However, the non-public APIs are liable to change between updates and implementations, so pretty much pointless and absolutely non-elegant.
If you want Native IO use the NIO classes.