【问题标题】:Can a java object be accessed from native code and vice versa?可以从本机代码访问 java 对象,反之亦然?
【发布时间】:2017-07-14 14:21:17
【问题描述】:

如果Java堆中存在对象X,并且如果我知道Java堆中对象X的地址,那么本机代码是否可以直接从内存中访问该对象而不涉及JNI?反之亦然,如果java代码确实知道对象Y在native heap上的地址,java是否可以在不涉及JNI的情况下访问它?

更准确地说,“java 对象是否以与本机对象相同的方式存储在内存中,还是有什么不同?”。如果没有,java和native中的byteArray对象不会以相同的方式存储吗?

请提供您的建议和参考。

编辑:这可能是正确的问题,为什么需要通过 JNI 将对象从 Java 堆转移到本机堆?为什么原生堆不能直接访问java堆对象?

【问题讨论】:

  • 不,尝试阅读docs.oracle.com/javase/tutorialjava没有像C++这样的指针,你为什么要这样编程?什么大任务?
  • 为什么你想这样做并绕过 JNI?这看起来像 XY problem.
  • @AndrewHenle,编辑了问题。

标签: java c++ operating-system java-native-interface


【解决方案1】:

Java 代码可以访问本机对象吗?不会。Java 代码由 JVM 管理。 (更准确地说,它是字节码,而不是 Java 代码。)JVM 的规范不允许字节码访问任意内存。字节码甚至不能访问 JVM 堆上的任意地址。比如私有字段只能被同一个类中的字节码访问。

能否本机代码直接访问 JVM 堆对象(没有 JNI)?是的。本机代码与 JVM 在相同的进程和地址空间中运行。据我所知,在大多数操作系统和硬件平台上,这意味着本机代码可以在该地址空间中执行任何操作。

应该本机代码直接访问 JVM 堆对象吗?绝对不是。

首先,JVM 规范没有指定对象在 JVM 堆上的布局,甚至没有指定字节数组。例如,JVM 可以将数组拆分成块,并在字节码使用数组时透明地转换地址。如果您尝试编写访问数组的本机代码,则必须重新实现该转换。这样的代码可能在一个 JVM 实现中工作,但可能不在另一个实现中,或者甚至可能在同一 JVM 的较新版本中,或者在以不同配置运行时在同一 JVM 中。这就是您必须使用 JNI 的原因之一:它为本地代码提供了 JVM 堆上对象的明确定义的“视图”。

其次,JVM 垃圾收集器可以随时在堆上移动对象。本机代码应通过句柄访问 JVM 堆对象。垃圾收集器知道它并在必要时更新句柄。试图绕过句柄的本机代码永远无法确定对象是否仍然存在。

第三个问题是本机代码直接修改 JVM 堆上对象之间的指针。根据垃圾收集器算法,这可能会导致各种问题。

简而言之:您可能可以直接从本机代码访问 JVM 堆对象,但您几乎可以肯定不应该

【讨论】:

  • 非常感谢乔娜。
【解决方案2】:

简短回答:不。

除了是 Java/C++ 问题之外,这与基本的操作系统概念相矛盾。由于每个进程都有自己的地址空间,一个进程无法访问其他进程的任何对象。

只有当进程(试图访问其他内存)在内核空间中运行并且底层操作系统允许操作,或者涉及某些实用程序(如“共享内存”)时,才能减轻此限制。即使是这种情况,您也会面临virtual address space 问题。内存的相同物理部分在不同进程中使用不同的值寻址。这就是为什么,如果你认为你知道一个对象的地址,那么这个地址是虚拟的,在其他进程中是无用的。

编辑:如果它们不在不同的进程中,那么答案肯定是肯定的。从理论上讲,您可以实现自己的 JNI :)。

【讨论】:

  • 问题不是指两个不同的过程。它只是一个 java 进程。
【解决方案3】:

一个可能的答案是使用 APR(Apache Portable Runtime)是的,我知道它是基于 JNI 的,但它有共享内存的概念。因此可以绑定另一个程序创建的共享内存空间(反之亦然)

https://apr.apache.org/docs/apr/1.5/group__apr__shm.html

在 JNI 部分之外,这似乎是不可能的。

【讨论】:

  • APR 与 JNI 无关。
  • @JonaChristopherSahnwaldt 以及您认为 JVM 如何访问 APR 中的 .dll 或 .so ?
  • 请解释一下JVM和APR的关系。抱歉,您似乎不知道自己在说什么。
  • 看看 APR 库的这一部分:apr.apache.org/docs/apr/2.0/group__apr__pools.html,请不要忘记对象只是“内存结构”......所以是的 java 可以访问本机对象,因为你必须要么将 JNI 包装器写入可以访问共享内存的 SO 或 DLL,然后您必须对内存进行解码以满足您的需求。
  • 您链接的代码与 Java、JVM 或 JNI 无关。
猜你喜欢
  • 2015-01-12
  • 1970-01-01
  • 2018-02-10
  • 2013-04-16
  • 2015-03-05
  • 2013-08-09
  • 1970-01-01
  • 2012-11-09
  • 2017-01-08
相关资源
最近更新 更多