指定Java内存分配池地址

发布于 2024-10-10 06:59:32 字数 709 浏览 9 评论 0原文

使用 -Xms-Xmx 选项,可以设置内存分配池的初始大小和最大大小。在 Linux 和 AIX 上使用 strace/truss 我发现,JVM 内部使用 (k)mmap 系统调用。 地址参数为NULL,因此操作系统决定将内存映射到哪个虚拟内存地址。

$ truss java -Xmx512M Hello 2>&1 | grep mmap
kmmap(0x00000000, 536870912, 3, 17, -1, 0x00000000, 0x00000000) = 0xB0000000

可以指定这个地址吗?

背景:我必须通过 Java 本机接口 (JNI) 调用遗留代码,这需要映射到内存中特定位置的大量不可重定位数据(32 位地址空间中的 2 GB)。该区域与Java内存分配池的位置重叠。

编辑:这是实际的内存布局:

0x0... AIX
0x1... Text
0x2... Stack
0x3... Heap
0x4... Heap
...... Legacy Data (2 GB)
0xd... Shared Library Text
0xe... unused
0xf... Shared Library Data

我的目标是将Java内存分配池从0xb/0xc移动到0x3/0x4段,这在标准(非大)内存模型中也可用。

With the -Xms and -Xmx Options, it is possible to set the initial and maximum size of the memory allocation pool. Using strace/truss on Linux and AIX I found out, the JVM internally uses the (k)mmap system call. The address-Parameter is NULL, therefore the operating system decides, at which virtual memory address it maps the memory.

$ truss java -Xmx512M Hello 2>&1 | grep mmap
kmmap(0x00000000, 536870912, 3, 17, -1, 0x00000000, 0x00000000) = 0xB0000000

Is is possible, to specify this address?

Background: I have to call legacy code via the Java Native Interface (JNI), which requires huge amounts of non-relocateable data (2 GB in a 32 bit address space) mapped at a specific location in memory. This region overlaps with the location of Javas memory allocation pool.

Edit: This is the actual memory layout:

0x0... AIX
0x1... Text
0x2... Stack
0x3... Heap
0x4... Heap
...... Legacy Data (2 GB)
0xd... Shared Library Text
0xe... unused
0xf... Shared Library Data

My goal is to move the Java memory allocation pool from 0xb/0xc into the 0x3/0x4 segments, which is also available in the standard (non large) memory model.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

呆萌少年 2024-10-17 06:59:33

也许你可以彻底解决这个问题。启动一个本机进程,并执行您需要执行的操作来保留不可协商的空间(mmap 或其他)。然后使用 Java 的 调用 API 来在本机进程中创建并启动 JVM。我找不到任何关于 JVM 如何进行内存管理的文档,但是 这是有道理的 它会很好地处理主机进程已经分配的内存(我猜它只是使用本地 malloc),所以它会找到其他地方来放置它的堆。如果您未分配 0x3-0x4 区域,您可以希望它会将其放在那里。

然而,我认为存在一个真正的风险,即内存模型中没有足够的地址空间供 JVM 使用。 0x3-0x4 区域是,什么,512 MB?如果你可以在其中容纳整个 JVM(堆、堆栈、perm、VM 结构等),那么很好,但如果不能,你可能会发现当 JVM 无法为堆分配连续内存时,它会变得非常沮丧。或者也可能不会。我真的不知道。

因此,在提出这一建议后,我强烈建议您不要这样做,而是遵循 sleske的建议并将本机代码放在单独的进程中。

Perhaps you could turn this problem inside-out. Start a native process, and do what you need to do to reserve your non-negotiable space (mmap or whatever). Then use Java's invocation API to create and start a JVM inside your native process. I can't find any documentation about how that JVM does its memory management, but it stands to reason that it will play nicely with memory that has already been allocated by the host process (i would guess it just uses the local malloc), so it will find somewhere else to put its heap. If you leave the 0x3-0x4 region unallocated, you can hope it will put it there.

However, i think there's a real risk that there just isn't enough address space left in your memory model for a JVM. The 0x3-0x4 region is, what, 512 MB? If you can fit a whole JVM (heap, stack, perm, VM structures, etc) in there, then fine, but if not, you may find that when the JVM can't allocate contiguous memory for the heap, it gets very upset. Or it may not. I really don't know.

So, having suggested this, i would strongly recommend that you don't do it, and instead follow sleske's advice and put the native code in a separate process.

旧梦荧光笔 2024-10-17 06:59:33

就我个人而言,我从未听说过配置分配池地址的方法。如果有这样的设定,恐怕会很晦涩难懂。

唯一确定的方法是查看 JDK/JRE 的源代码,可从 http://hg 获取。 openjdk.java.net/ 。如果 NULL 参数是硬编码的,那么你就不走运了。

对于替代解决方案,如果您无法修复行为不当的本机代码:

您可以编写一个小型本机程序来调用您的本机代码,然后从 Java 调用该程序(通过 Runtime.exec)。这样,顽皮的代码就可以获得自己的操作系统进程和单独的地址空间。当然,这只有在本机代码和 Java 之间没有太多来回的情况下才可行。

或者将代码放入与 Java 应用程序并行运行的小型服务器中,以便两者可以通信...

附加说明:

我刚刚在 mmap 的联机帮助页中注意到不一定支持向 mmap 提供地址:

MAP_FIXED:准确解释addr。
[...]
是否由实现定义
应支持 MAP_FIXED。
MAP_FIXED 应支持
符合 XSI 的系统。 [...] 什么时候
MAP_FIXED 未设置,
实现中使用 addr
实现定义的方式
到达宾夕法尼亚州。

http://linux.die.net/man/3/mmap

所以即使你设法让 JVM 使用某个地址调用 mmap,但这可能仍然不会成功。

Personally, I have never heard of a way to configure the allocation pool address. If there is such a setting, it's probably very obscure.

The only way to be sure is to look at the source of the JDK/JRE, available at http://hg.openjdk.java.net/ . If the NULL parameter is hardcoded, you're out of luck.

For an alternative solution, if you cannot fix the misbehaved native code:

You could write a small native program to call your native code, then call the program from Java (via Runtime.exec). That way the naughty code gets its own OS process with separate addresss space. Of course that's only feasible if there's not too much back-and-forth between native code and Java.

Or make the code into a small server that runs in parallel to your Java app, so the two can communicate...

Additional note:

I just noticed in the manpage of mmap that giving an address to mmap is not necessarily supported:

MAP_FIXED: Interpret addr exactly.
[...]
It is implementation-defined whether
MAP_FIXED shall be supported.
MAP_FIXED shall be supported on
XSI-conformant systems. [...] When
MAP_FIXED is not set, the
implementation uses addr in an
implementation-defined manner to
arrive at pa.

http://linux.die.net/man/3/mmap

So even if you manage to let the JVM call mmap with a certain address, that may still not succeed.

无人接听 2024-10-17 06:59:33

您可以尝试的一个想法是使用 LD_PRELOAD 来注入您自己的 kmmap 行为。 Google 提供了一个 LD_PRELOAD 示例,用于在 TCMalloc 项目中注入自定义 malloc。

One idea you can try is to use an LD_PRELOAD to inject your own kmmap behavior. Google provides an example of the LD_PRELOAD to inject a custom malloc in the TCMalloc project.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文