固定不安全的指针
Pinning Unsafe pointer
我正在设计一个JNI接口,它将字符串参数从Java传递到C++。我需要高性能,并且已经能够使用Direct ByteBuffer和String.getBytes()很好地做到这一点,但将字符串传递到C/C++的代价仍然很高。我最近读到了OpenJDK的Unsafe类。这个优秀的页面让我开始了,但我发现《不安全》很糟糕,但可以理解的是,它的文档记录得很差。
我想知道,如果我使用Unsafe类获得一个指向字符串的指针并将其传递给C++,是否存在在输入C++代码之前对象已经移动的风险?即使在C++执行的时候?或者这些地址是由不安全代码提供的?如果它们没有被固定,那么这些不安全的指针怎么会有用呢?
Unsafe并不意味着与JNI进行互操作。因此,通过Unsafe获得的内容可能随时更改(即使与C++并行)。
JNI API能够将对象固定在内存中以访问数组内容(在HotSpot JVM中,它会阻止GC,因此可能会对GC暂停时间产生负面影响)。
特别是,Get*ArrayElements会固定数组,直到您明确执行Release*ArrayElement。GetStringChars的工作方式类似。
直接ByteBuffer持有指向堆外内存缓冲区的指针,前提是该缓冲区没有移动,您可以访问它以获取本机代码。
我已经阅读了Java.misc.Unsafe的Java源代码,并有了更多的见解。
Unsafe至少有两种处理内存的方法。
-
allocateMemory/reallocateMemoory/freeMemory/etc/strong>——据我所知,这种内存分配是在堆外的,因此不会面临GC’ing挑战。我已经间接地测试了这一点,似乎长返回只是指向内存的指针。这种类型的内存很可能可以安全地通过JNI传递给本机代码。应用程序Java代码应该能够通过使用其他一些支持这种内存指针风格的内在不安全方法,在JNI调用前后快速修改/查询它。
-
object+offset-这些方法接受一个指向对象的指针和一个"offset"标记,以指示在对象中的何处获取/修改值。对象可能总是在Java堆中,但将对象传递给这些方法可能有助于解决GC的复杂性。听起来"偏移量"有时是一个"cookie",而不是一个实际的偏移量,但在数组的情况下,arrayBaseOffset()也会返回一个可以算术运算的"偏移"。我不知道这个对象+偏移量对于JNI代码是否安全。我看不到一种方法可以直接生成指向堆中Java对象的指针,而该指针可能(危险地)通过JNI。可以传递一个对象和偏移,但考虑到通过JNI传递对象的成本,这种方法无论如何都没有吸引力。
像(1)一样,与我在帖子中引用的页面相关的代码对于JNI交互来说可能是非常安全的。它在处理String时采用对象+偏移量的方法,但在处理直接ByteBuffer时使用方法(1),后者总是位于Java堆之外。Direct ByteBuffer对JNI非常友好,通常可以避免我在上面对Tom的评论中提到的JNI对象传递成本。
- 为什么指针不写入类的地址?
- 在函数结束后使用指向变量的指针是否安全?
- 为什么"具有常量成员的结构"类型的指针不能指向"具有非常量成员的结构"?
- 当目标指针不是基类的类型时,为什么允许dynamic_cast为多态类生成 null 指针?
- C++/CLI 和 C#/VB 与不安全和外部有什么区别?
- 比较两个 constexpr 指针不是 constexpr?
- 为什么智能指针不能用通常的指针方式声明
- 问:Apache Arrow 数组生成器不安全追加
- 不安全的 MPI 非阻塞通信示例?
- 字符指针不递增?
- C++为什么原始指针不会增加shared_ptr的引用计数?
- 为什么在C++中使用delete后指针不为NULL
- 堆指针不会被分配给数组有什么原因吗
- 有没有一种简单的方法来检查C++中的不安全表达式
- 在特殊情况下使析构函数不是虚拟的,并删除基指针是否安全
- 为什么将指针铸成数字类型是不安全的
- 固定不安全的指针
- 将类指针转换为字符指针(不安全)
- 在哪些体系结构上计算无效指针不安全
- 我应该用 C/C++ 重写我的 DSP 例程,还是擅长使用 C# 不安全指针?