2023-01-19 330
在尝试JNI界面时,我想知道是否可以服用JObject并将其转换为等效的结构来操纵字段.但是,当我尝试时,我很惊讶地看到这无效. 忽略这个想法有多可怕,为什么不起作用?
我做了一个简单的类Point进行测试. Point有两个字段和一个构造函数,可以采用X和Y以及一些随机方法,这些方法基于字段返回信息.
public class Point {
public final double x;
public final double y;
// As well as some random methods
}
使用Jol,我在Java运行时找到了我的Point类的结构(如下所示).
C:\Users\home\IdeaProjects\test-project>java -cp jol-cli-0.9-full.jar;out\production\java-test org.openjdk.jol.Main internals Point
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Instantiated the sample instance via public Point(double,double)
Point object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 31 32 01 f8 (00110001 00110010 00000001 11111000) (-134139343)
12 4 (alignment/padding gap)
16 8 double Point.x 0.0
24 8 double Point.y 0.0
Instance size: 32 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
我写出了一个简单的测试结构,该结构与JOL描述的内存模型以及一些测试相匹配,以确保其具有相同的对齐方式,并且每个元素都具有正确的偏移.我使用Rust做到了,但是对于任何其他编译的语言都应该相同.
#[derive(Debug)]
#[repr(C, align(8))]
pub struct Point {
header1: u32,
header2: u32,
header3: u32,
point_x: f64,
point_y: f64,
}
我的测试的最后一部分是制作一个JNI函数,该函数吸收了Point对象并将点对象传输到点结构.
/*
* Class: Main
* Method: analyze
* Signature: (LPoint;)V
*/
JNIEXPORT void JNICALL Java_Main_analyze
(JNIEnv *, jclass, jobject);
#[no_mangle]
pub extern "system" fn Java_Main_analyze(env: JNIEnv, class: JClass, obj: JObject) {
unsafe {
// De-reference the `JObject` to get the object pointer, then transmute the
// pointer into my `Point` struct.
let obj_ptr = mem::transmute::<_, *const Point>(*obj);
// Output the debug format of the `Point` struct
println!("{:?}", *obj_ptr);
}
}
每次运行时,我都会得到不同的结果.
// First Run:
Point { header1: 1802087032, header2: 7, header3: 43906792, point_x:
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000230641669, point_y:
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000021692881 }
// Second Run:
Point { header1: 1802087832, header2: 7, header3: 42529864, point_x:
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000229832192, point_y:
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000021012588 }
C:\Users\home\IdeaProjects\test-project>java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
编辑:我在Windows 10 Home 10.0.18362 Build 18362
上做到了这一点
编辑2:,由于我使用Rust来解决此问题,因此我使用了Rust的 板条箱.它提供了上面提到的JObject类型.我只是想到可能会有一些混乱,因为JObject与C头中显示的jobject不同. JObject是围绕着jobject的指针的生锈包装器,因此我在传输指针之前对其进行删除.
阅读 paper paper 在记忆压实方面,我了解到Java参考是由两个指针组成的.
在垃圾收集期间,发生了一个压实步骤.为了确保参考仍将排队,使用两个指针来防止在移动对象时进行操作.引用由指向对象的另一个指针指针组成.当发生压实步骤并通过内存移动对象时,只需要更改第二个指针.
换句话说,参考实际上是指向对象的内存位置的指针.
我知道我对此解释了,但希望它大多是可读/准确的.
#[no_mangle]
pub extern "system" fn Java_Main_analyze(env: JNIEnv, class: JClass, obj: JObject) {
unsafe {
// It should have been transmuted to a pointer to a pointer and dereferenced twice.
let indirect = mem::transmute::<_, *const *const Point>(*obj);
println!("{:?}", **indirect);
}
}
应用该修复程序后,对象数据就开始正确排列. X和Y与测试对象相同,并且所有三个标题都与JOL对内存格式的预测进行了排列(我假设如果我使用了签名的整数,标题3将是相同的).
>
Point { header1: 1, header2: 0, header3: 4160799044, point_x: -3.472, point_y: 4.0 }
响应@botje :我的Point struct是正确的,但是您无法重新创建错误,因为您从一开始就正确解决了问题,而我却没有.
以上所述是小编给大家介绍的JNI对象指针,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!
原文链接:https://77isp.com/post/25892.html
=========================================
https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。
数据库技术 2022-03-28
网站技术 2022-11-26
网站技术 2023-01-07
网站技术 2022-11-17
Windows相关 2022-02-23
网站技术 2023-01-14
Windows相关 2022-02-16
Windows相关 2022-02-16
Linux相关 2022-02-27
数据库技术 2022-02-20
抠敌 2023年10月23日
嚼餐 2023年10月23日
男忌 2023年10月22日
瓮仆 2023年10月22日
簿偌 2023年10月22日
扫码二维码
获取最新动态