如果我们查看Java Object类,我们可以找到一些方法,例如:
public native int hashCode()
protected native Object clone()
这些本地方法是什么,这些方法如何工作?
如果我们查看Java Object类,我们可以找到一些方法,例如:
public native int hashCode()
protected native Object clone()
这些本地方法是什么,这些方法如何工作?
hashcode()
的情况下,这是由JVM实现的。这是因为哈希码通常与JVM所知道的某些内容相关。在早期的JVM上,这与对象在内存中的位置有关 - 在其他JVM上,对象可能会移动到内存中,因此可能会使用更复杂(但仍然非常快速)的方案。大多数本地方法都是使用JNI实现的,就像其他答案中提到的那样。
然而,诸如Object.hashCode
之类的性能关键方法通常被实现为内置函数。当字节码编译成机器码时,Java编译器会识别方法调用并直接内联适当的代码。这显然比通过JNI调用一个微不足道的方法要快得多。
许多人声称Object.hashCode
将返回内存中对象表示的地址。在现代实现中,对象实际上会在内存中移动。相反,对象头的一部分用于存储该值,该值可能在第一次请求该值时从内存地址懒洋洋地推导出来。
这些本地方法是什么?它们是如何工作的?
以下是最小示例,以便更清楚:
Main.java:
public class Main {
public native int square(int i);
public static void main(String[] args) {
System.loadLibrary("Main");
System.out.println(new Main().square(2));
}
}
Main.c:
->Main.c:
#include <jni.h>
#include "Main.h"
JNIEXPORT jint JNICALL Java_Main_square(
JNIEnv *env, jobject obj, jint i) {
return i * i;
}
编译并运行:
sudo apt-get install build-essential openjdk-7-jdk
export JAVA_HOME='/usr/lib/jvm/java-7-openjdk-amd64'
javac Main.java
javah -jni Main
gcc -shared -fpic -o libMain.so -I${JAVA_HOME}/include \
-I${JAVA_HOME}/include/linux Main.c
java -Djava.library.path=. Main
输出:
4
在Ubuntu 14.04上测试通过。同时也适用于Oracle JDK 1.8.0_45。
有一个GitHub示例供您使用。
解释:
它允许您:
这可以用于:
代价是较低的可移植性。
您还可以从C中调用Java,但必须首先在C中创建JVM:如何从C++调用Java函数?
以OpenJDK 8为例
让我们找出在jdk8u60-b27中定义了Object#clone
的位置。
首先我们找到:
find . -name Object.java
这导致我们来到jdk/src/share/classes/java/lang/Object.java#l212:
protected native Object clone() throws CloneNotSupportedException;
现在来到了最困难的部分,找出所有间接引用中clone所在的位置。帮助我的查询语句是:
find . -iname object.c
这将找到实现Object本地方法的C或C++文件。它将我们引导到jdk/share/native/java/lang/Object.c#l47:
static JNINativeMethod methods[] = {
...
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
}
这将引导我们到JVM_Clone
符号:
grep -R JVM_Clone
这导致我们跳转到 hotspot/src/share/vm/prims/jvm.cpp#l580:JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
JVMWrapper("JVM_Clone");
在扩展了一堆宏之后,我们得出结论,这是定义点。