- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我在 on IBM 上阅读那个
To access Java objects' fields and invoke their methods, native code must make calls to FindClass(), GetFieldID(), GetMethodId(), and GetStaticMethodID(). In the case of GetFieldID(), GetMethodID(), and GetStaticMethodID(), the IDs returned for a given class don't change for the lifetime of the JVM process. But the call to get the field or method can require significant work in the JVM, because fields and methods might have been inherited from superclasses, making the JVM walk up the class hierarchy to find them. Because the IDs are the same for a given class, you should look them up once and then reuse them. Similarly, looking up class objects can be expensive, so they should be cached as well.
如何缓存 JNI 中的methodID
、fieldID
和class
对象?是否有必须遵循的内置方法或特定程序?
最佳答案
没有可遵循的内置方法,但这里有一个标准、干净且可重复的实现,展示了我如何实践 IBM 的建议。
我将假设您从 Java 调用 DLL,并且在整个应用程序生命周期中多次引用它。
示例 Native Java 类名为 org.stackoverflow.jni.NativeClazz
,它将实现 2 个内置 JNI 方法 JNI_OnLoad()
和 JNI_OnUnload ()
.
void JNI_OnLoad(JavaVM *vm, void *reserved)
:该方法将用于将Class IDs注册为全局变量,并将Method IDs和Field IDs分配给静态变量。该方法在Java VM加载驱动时自动调用;它在驱动程序生命周期中只被调用一次。
void JNI_OnUnload(JavaVM *vm, void *reserved)
:此方法将用于释放 JNI_OnLoad()
注册的所有全局变量。 VM 将在应用程序关闭前立即自动调用 JNI_OnUnload()
。
理由:据我了解,必须将类 ID 注册为全局引用,以保持任何关联的方法 ID/字段 ID 的可行性。如果没有这样做并且类从 JVM 中卸载,则在类重新加载时,方法 ID/字段 ID 可能不同。如果 Class ID 注册为全局引用,则关联的 Method IDs 和 Field IDs 不需要注册为全局引用。将类 ID 注册为全局引用可防止卸载关联的 Java 类,从而稳定方法 ID/字段 ID 值。应在 JNI_OnUnload()
中删除全局引用,包括 Class ID。
方法 ID 和字段 ID 不由 native 代码管理;它们由虚拟机管理并且在关联类被卸载之前一直有效。在虚拟机卸载定义类之前,不能显式删除字段 ID 和方法 ID;它们可以在卸载后留给 VM 处理。
示例代码
以下 C++ 代码部分中的注释解释了全局注册变量。
这是代表数据对象的 Java 类 BeanObject
:
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
* Java class instances.
*/
public native void instanceNativeMethod(BeanObject bean);
}
这是在 NativeClazz
上使用 javah
生成的 C++ 头文件“org_stackoverflow_jni_NativeClazz.h
”: p>
/* 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; // declare for each class
static jmethodID JMID_BeanObject_getFoo; // declare for each class method
/**************************************************************
* 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);
}
关于java - 在 JNI 中,如何根据 IBM 的性能建议缓存类、方法 ID 和字段 ID?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10617735/
在有些场景下,我们需要对我们的varchar类型的字段做修改,而修改的结果为两个字段的拼接或者一个字段+字符串的拼接。 如下所示,我们希望将xx_role表中的name修改为name+id。
SELECT incMonth as Month, SUM( IF(item_type IN('typ1', 'typ2') AND incMonth = Month, 1, 0 ) )AS
我最近读到 volatile 字段是线程安全的,因为 When we use volatile keyword with a variable, all the threads read its va
我在一些模型中添加了一个 UUID 字段,然后使用 South 进行了迁移。我创建的任何新对象都正确填充了 UUID 字段。但是,我所有旧数据的 UUID 字段为空。 有没有办法为现有数据填充 UUI
刚刚将我的网站从 mysql_ 更新为 mysqli,并破坏了之前正常运行的查询。 我试图从旋转中提取 id,因为它每次都会增加 1,但我不断获取玩家 id,有人可以告诉我我做错了什么吗?我尝试了将
我在 Mac OS X 上使用带有 Sequel Pro 的 MySQL。我想将一个表中的一个字段(即名为“GAME_DY”的列)复制到另一个名为“DAY_ID”的表的空字段中。两个表都是同一数据库的
问题: 是否有可能有一个字段被 JPA 保留但被序列化跳过? 可以实现相反的效果(JPA 跳过字段而序列化则不会),如果使用此功能,那么相反的操作肯定会很有用。 类似这样的事情: @Entity cl
假设我有一个名为“dp”的表 Year | Month | Payment| Payer_ID | Payment_Recipient | 2008/2009 | July
我将尝试通过我的 Raspberry Pi 接入点保证一些 QoS。 开始之前,我先动手:我阅读了有关 tcp、udp 和 ip header 的内容。在IP header description我看
如果你能弄清楚如何重命名这个问题,我愿意接受建议。 在 Dart 语言中,可以编写一个带有 final 字段的类。这些是只能设置的字段构造函数前 body 跑。这可以在声明中(通常用于类中的静态常量)
你怎么样? 我有两个带有两个字段的日期选择器 我希望当用户选择 (From) 时,第二个字段 (TO) 将是 next day 。比如 booking.com 例如:当用户选择From 01-01-2
我想我已经看到了这个问题的一些答案,这些答案可能与我需要的相差不远,但我对 mysql 的了解还不够确定,所以我会根据我的具体情况提出问题。 我有一个包含多个表的数据库,为此,如果“image”表上的
我在 mySQL 数据库中有 2 个表: customers ============ customer_id (1, 2 ) customer_name (john, mark) orders ==
我正在开发一个员工目标 Web 应用程序。 领导/经理在与团队成员讨论后为他们设定目标。这是一年/半年/季度,具体取决于组织遵循的评估周期。 现在的问题是添加基于时间段的字段或存档上一季度/年度数据的
我正在寻找允许内容编辑器从媒体库中选择多个文件的东西,这些文件将在渲染中列出。他们还需要能够上传文件和搜索。它必须在页面编辑器(版本 8 中称为体验编辑器)中工作。 到目前为止我所考虑的: 一堆文件字
现在,我有以下由 original.df %.% group_by(Category) %.% tally() %.% arrange(desc(n)) 创建的 data.frame。 DF 5),
我想知道是否有一些步骤/解决方案可以处理错误消息并将它们放入 Pentaho 工具中的某个字符串或字段中?例如,如果连接到数据库时发生某些错误,则将该消息从登录到字符串/字段。 最佳答案 我们在作业的
如何制作像短信应用程序一样的“收件人”字段?例如,右侧有一个“+”按钮,当添加某人时,名称将突出显示并可单击,如圆角矩形等。有没有内置的框架? 最佳答案 不,但请参阅 Three20 的 TTMess
是否可以获取记录的元素或字段的列表 通过类型信息类似于类的已发布属性的列表吗? 谢谢 ! 最佳答案 取决于您的delphi版本,如果您使用的是delphi 2010或更高版本,则可以使用“新rtti”
我正在构建一个 SQLite 数据库来保存我的房地产经纪人的列表。我已经能够使用外键来识别每个代理的列表,但我想在每个代理的记录中创建一个列表;从代理商和列表之间的一对一关系转变为一对多关系。 看这里
我是一名优秀的程序员,十分优秀!