嚴華 发表于 2024-10-31 09:26:22

《JVM第6课》当地方法栈

1 什么是当地方法

起首要知道什么是当地方法,当地方法并不是 JVM 自己的方法,也不是 jre 内里的方法,而是指那些操作体系自己的方法(如C/C++方法),它们在操作体系目录里。可以这么理解,当地方法就是计算机操作体系对外提供的方法,JVM 通过调用这些方法可以实现 Java 程序和计算机的交互。
1.1 当地方法的利益


[*]访问操作体系资源:直接调用操作体系的API,例如文件体系、网络接口、图形用户界面等。
[*]性能优化:对于某些计算密集型任务,利用C或C++等语言实现可以显著提高性能。
[*]利用现有库:利用已经存在的C/C++库,避免重复开发和维护。
[*]硬件访问:直接访问硬件设备,例如摄像头、传感器等。
所以如果我们想优化计算密集型任务的性能,或是调用 Java 中没有实现的计算机功能,我们可以自己实现一个当地方法。
1.2 声明当地方法

在Java中,当地方法通过native关键字声明。例如:
public class MyClass {
    // 声明本地方法
    public native void nativeMethod();

    // 静态块中加载本地库
    static {
      System.loadLibrary("mylib"); // 加载名为mylib的本地库
    }

    public static void main(String[] args) {
      new MyClass().nativeMethod(); // 调用本地方法
    }
}1.3 实现当地方法

当地方法的实现通常利用JNI(Java Native Interface)或JNA(Java Native Access)来完成。以下是利用JNI实现当地方法的步骤:
1. 生成头文件

利用javah工具生成包罗当地方法署名的C头文件。假设上面的Java类保存为MyClass.java,编译后生成MyClass.class,然后运行:
javah -jni MyClass这将生成一个名为MyClass.h的头文件,内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MyClass */

#ifndef _Included_MyClass
#define _Included_MyClass
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:   MyClass
* Method:    nativeMethod
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_MyClass_nativeMethod
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif2. 编写C语言实现

根据生成的头文件,编写C语言实现。例如:
#include <jni.h>
#include <stdio.h>
#include "MyClass.h"

// 实现本地方法
JNIEXPORT void JNICALL Java_MyClass_nativeMethod(JNIEnv *env, jobject obj) {
    printf("Hello from native method!\n");
}3. 编译C代码

将C代码编译成动态链接库。假设C文件名为mylib.c,编译命令如下:
在Linux上:
gcc -shared -o libmylib.so -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux mylib.c在Windows上:
cl -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -LD mylib.c -Fe mylib.dll4. 运行Java程序

确保动态链接库在Java程序的库路径中,然后运行Java程序:
java -Djava.library.path=. MyClass1.4 利用JNA

JNA是一种更简单的方式来调用当地库,不需要编写C代码。以下是一个利用JNA的示例:

[*]添加JNA依赖:在项目中添加JNA的依赖。如果你利用Maven,可以在pom.xml中添加:
<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.8.0</version>
</dependency>
[*]界说接口:界说一个接口来映射当地库中的函数。
import com.sun.jna.Library;
import com.sun.jna.Native;

public interface MyLib extends Library {
    MyLib INSTANCE = Native.load("mylib", MyLib.class);

    void nativeMethod();
}
[*]调用当地方法:
public class MyClass {
    public static void main(String[] args) {
      MyLib.INSTANCE.nativeMethod(); // 调用本地方法
    }
}1.5 总结

当地方法是Java程序中的一种特殊方法,其声明在Java代码中,但实现由非Java语言编写。通过当地方法,Java程序可以访问操作体系资源、优化性能、利用现有库和直接访问硬件设备。常见的实现方式包罗JNI和JNA。
2 当地方法栈

2.1 特点


[*]线程私有:每个线程都有自己的当地方法栈,与Java虚拟机栈一样,当地方法栈也是线程私有的。
[*]存储结构:当地方法栈中的每个栈帧(Frame)对应一次当地方法的调用。栈帧中包罗当地方法的参数、局部变量、操作数栈等信息。
[*]调用机制:当Java代码调用一个当地方法时,JVM会创建一个新的栈帧并将其压入当地方法栈。当地方法实行完毕后,栈帧会被弹出并丢弃。
2.2 当地方法栈与Java虚拟机栈的区别


[*]用途不同:Java虚拟机栈用于支持Java方法的实行,而当地方法栈用于支持当地方法的实行。
[*]实现方式:Java虚拟机栈的实现由JVM规范规定,而当地方法栈的实现通常依赖于详细的JVM实现和操作体系的ABI(Application Binary Interface)。
[*]数据类型:Java虚拟机栈重要处理Java类型的值,而当地方法栈可能涉及更广泛的C/C++类型或其他原生类型。
2.3 当地方法栈的工作流程


[*]方法调用:当Java代码中调用一个声明为native的方法时,JVM会查找该方法的当地实现。
[*]栈帧创建:JVM为当地方法创建一个新的栈帧,并将其压入当地方法栈。
[*]参数传递:调用当地方法所需的参数会被从Java虚拟机栈复制到当地方法栈的栈帧中。
[*]方法实行:当地方法在当地方法栈中实行,可以访问操作体系资源、硬件设备等。
[*]结果返回:当地方法实行完毕后,结果会被从当地方法栈复制回Java虚拟机栈,然后继承实行Java代码。
[*]栈帧弹出:当地方法栈中的栈帧被弹出并丢弃。
2.4 总结

当地方法栈是JVM中用于支持当地方法调用的重要数据结构。通过当地方法栈,Java程序可以调用用其他语言编写的代码,从而实现更广泛的功能和更高的性能。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 《JVM第6课》当地方法栈