我在IBM上读到
要访问Java对象的字段并调用其方法,本机代码必须调用FindClass(),GetFieldID(),GetMethodId()和GetStaticMethodID()。对于GetFieldID(),GetMethodID()和GetStaticMethodID(),对于给定类返回的ID在JVM进程的生存期内不会更改。但是,获取字段或方法的调用可能需要在JVM中进行大量工作,因为字段和方法可能是从超类继承的,从而使JVM遍历类层次结构来查找它们。因为给定类的ID是相同的,所以您应该先查找一次然后重用它们。同样,查找类对象可能很昂贵,因此也应该对其进行缓存。
一个人如何 缓存 的methodID
,fieldID
以及class
在JNI对象?是否有必须遵循的内置方法或特定过程?
没有可遵循的内置方法,但是这里有一些标准,简洁和可重复的实现,显示了我如何实践IBM的建议。
我假设您正在从Java调用DLL,并且在整个应用程序生命周期中多次引用它。
命名示例Native Java Class
org.stackoverflow.jni.NativeClazz
,它将实现2个内置JNI方法JNI_OnLoad()
和JNI_OnUnload()
。
void JNI_OnLoad(JavaVM * vm,void * reserved):
此方法将用于将类ID注册为全局变量,并将方法ID和字段ID分配给静态变量。当Java VM加载驱动程序时,将自动调用该方法。在驱动程序生命周期中仅调用一次。
void JNI_OnUnload(JavaVM * vm,void * reserved):
此方法将用于释放由注册的所有全局变量JNI_OnLoad()
。VM将JNI_OnUnload()
在应用程序关闭之前立即自动调用。
原理: 我的理解是必须将类ID注册为全局引用,以维护任何关联的方法ID
/字段ID的可行性。如果不这样做,并且从JVM卸载了类,则在重新加载类时,方法ID
/字段ID可能会不同。如果将类ID注册为全局引用,则不需要将关联的方法ID和字段ID注册为全局引用。将类ID注册为全局引用可以防止关联的Java类卸载,因此可以稳定方法ID
/字段ID的值。包括类ID在内的全局引用应在中删除JNI_OnUnload()
。
方法ID和字段ID不受本机代码管理;它们由虚拟机管理,并且在卸载相关的类之前一直有效。在虚拟机卸载定义类之前,无法显式删除字段ID和方法ID。卸载后,它们可以留给VM处理。
样例代码
以下C ++代码部分中的注释说明了全局注册变量。
这是BeanObject
表示数据对象的Java类:
package org.stackoverflow.data;
public class BeanObject {
String foo = "";
public String getFoo() {
return foo;
}
}
这是一个基本的Java类NativeClazz
:
package org.stackoverflow.jni;
import org.stackoverflow.data.BeanObject;
public class NativeClazz {
// Static area for forced initialization
static {
// Load Native Library (C++); calls JNI_OnLoad()
System.loadLibrary("Native_Library_File_Name");
}
/**
* A static native method you plan to call.
*/
public static native void staticNativeMethod(BeanObject bean);
/**
* A non-static native method you plan to call, to show this also works with
* instantiated Java classes.
*/
public native void instanceNativeMethod(BeanObject bean);
}
这是使用javah
on 生成的C ++头文件NativeClazz
:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_stackoverflow_jni_NativeClazz */
#ifndef _Included_org_stackoverflow_jni_NativeClazz
#define _Included_org_stackoverflow_jni_NativeClazz
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_stackoverflow_jni_NativeClazz_staticNativeMethod
* Method: staticNativeMethod
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_stackoverflow_jni_NativeClazz_staticNativeMethod
(JNIEnv *, jclass, jobject);
/*
* Class: org_stackoverflow_jni_NativeClazz_instanceNativeMethod
* Method: instanceNativeMethod
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_stackoverflow_jni_NativeClazz_instanceNativeMethod
(JNIEnv *, jobject, jobject);
#ifdef __cplusplus
}
#endif
#endif
这是实现头文件的C ++ .cpp文件:
#include "org_stackoverflow_jni_NativeClazz.h"
using namespace std;
/**************************************************************
* Static Global Variables to cache Java Class and Method IDs
**************************************************************/
static jclass JC_BeanObject;
static jmethodID JMID_BeanObject_getFoo;
/**************************************************************
* Declare JNI_VERSION for use in JNI_Onload/JNI_OnUnLoad
* Change value if a Java upgrade requires it (prior: JNI_VERSION_1_6)
**************************************************************/
static jint JNI_VERSION = JNI_VERSION_1_8;
/**************************************************************
* Initialize the static Class and Method Id variables
**************************************************************/
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
// Obtain the JNIEnv from the VM and confirm JNI_VERSION
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION) != JNI_OK) {
return JNI_ERR;
}
// Temporary local reference holder
jclass tempLocalClassRef;
// STEP 1/3 : Load the class id
tempLocalClassRef = env->FindClass("org/stackoverflow/data/BeanObject");
// STEP 2/3 : Assign the ClassId as a Global Reference
JC_BeanObject = (jclass) env->NewGlobalRef(tempLocalClassRef);
// STEP 3/3 : Delete the no longer needed local reference
env->DeleteLocalRef(tempLocalClassRef);
// Load the method id
JMID_BeanObject_getFoo = env->GetMethodID(JC_BeanObject, "getFoo", "(Ljava/lang/String;)V");
// ... repeat prior line for any other methods of BeanObject
// ... repeat STEPS 1-3 for any other classes; re-use tempLocalClassRef.
// Return the JNI Version as required by method
return JNI_VERSION;
}
/**************************************************************
* Destroy the global static Class Id variables
**************************************************************/
void JNI_OnUnload(JavaVM *vm, void *reserved) {
// Obtain the JNIEnv from the VM
// NOTE: some re-do the JNI Version check here, but I find that redundant
JNIEnv* env;
vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION);
// Destroy the global references
env->DeleteGlobalRef(JC_BeanObject);
// ... repeat for any other global references
}
/**************************************************************
* A Static Native Method
**************************************************************/
JNIEXPORT void JNICALL Java_org_stackoverflow_jni_NativeClazz_staticNativeMethod
(JNIEnv * env, jclass clazz, jobject jBeanObject) {
// Retrieve jstring from the Java Object
jstring jFoo = (jstring)env->CallObjectMethod(jBeanObject, JMID_BeanObject_getFoo);
// Make accessible to C++
const char * cFoo = env->GetStringUTFChars(jFoo, NULL);
// Do something with cFoo...
// Release Resources
env->ReleaseStringUTFChars(jFoo, cFoo);
env->DeleteLocalRef(jFoo);
}
/**************************************************************
* Instance / Non-Static Native Method
**************************************************************/
JNIEXPORT void JNICALL Java_org_stackoverflow_jni_NativeClazz_instanceNativeMethod
(JNIEnv * env, jobject selfReference, jobject jBeanObject) {
// Retrieve jstring from the Java Object
jstring jFoo = (jstring)env->CallObjectMethod(jBeanObject, JMID_BeanObject_getFoo);
// Make accessible to C++
const char * cFoo = env->GetStringUTFChars(jFoo, NULL);
// Do something with cFoo...
// Release Resources
env->ReleaseStringUTFChars(jFoo, cFoo);
env->DeleteLocalRef(jFoo);
}
我看了IBM 要访问Java对象的字段并调用它们的方法,本机代码必须调用FindClass()、GetFieldID()、GetMachodId()和GetStaticMachodID()。在GetFieldID()、GetMachodID()和GetStaticMachodID()的情况下,为给定类返回的ID在JVM进程的生命周期内不会改变。但是获取字段或方法的调用可能需要在JVM中进行大量工作
我想跨调用缓存方法ID。为此,我得到方法ID: 我的问题是:我是否需要使用NewGlobalRef创建全局引用,或者可以从本地引用获取并保存方法ID(我使用FindClass获取class\u HelloWorld),而不需要全局引用类元数据?
本文向大家介绍微信小程序实现缓存根据不同的id来进行设置和读取缓存,包括了微信小程序实现缓存根据不同的id来进行设置和读取缓存的使用技巧和注意事项,需要的朋友参考一下 本文是根据不同的id来进行设置和读取缓存,是同步缓存的方式: jonNums.count 是接口返回的数据 是报名总人数 newNumber 新的报名总人数 - 缓存上次的报名总人数 = 新增报名人数 感谢阅读,希望能帮助到大家
嗨,为了保持向后兼容性,可以更改协议缓冲区中字段的数据类型吗。例如 旧消息 所以基本上我没有更改字段的标签号,也没有重命名它,但我更改了数据类型。那么这是向后兼容的吗?如果一个应用程序获得了一个用以前的模式创建的旧proto对象,它可以通过这个新模式创建的对象进行解析吗?
问题内容: 假设使用Microsoft SQL Server 2008,有一个table1保留选定的省,地区,公社和村庄的ID。然后是表2,其中包含省,区,公社和村庄的ID和名称。省和地区是必填字段,并且始终会被填写。公社和村庄可能会被填补,但由于不需要,甚至可能不会被填补。 在不知道表1中是否填写公社和村庄的ID的情况下,构建动态SQL语句的最佳方法是什么。 如果未填写表1中的ID,此语句将给出
问题内容: 在对fielddata与doc_values进行的一些实验中,我遇到了一个奇怪的情况。在我以前的映射中,我根本没有使用doc值。在新的映射中,我已添加到映射中的所有字段,但分析的字符串字段和布尔值(直到2.0才受支持)除外。 因此,详细而言,这是我的处理方式: 重新索引所有数据之前,我重新启动了ES 1.7集群,并使用排序,聚合和脚本字段运行查询以“预热”字段数据缓存。然后,我询问端点