指定Java内存分配池地址

时间:2011-01-03 15:11:44

标签: java java-native-interface mmap

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

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

是否可以指定此地址?

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

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

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段,这在标准(非大型)内存模型中也可用。

3 个答案:

答案 0 :(得分:2)

就个人而言,我从未听说过配置分配池地址的方法。如果有这样的设置,它可能非常模糊。

唯一可以确定的方法是查看http://hg.openjdk.java.net/处提供的JDK / JRE的来源。如果NULL参数是硬编码的,那你就不走运了。

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

您可以编写一个小的本机程序来调用您的本机代码,然后从Java调用该程序(通过Runtime.exec)。这样,顽皮的代码获得了自己的OS进程,并具有单独的地址空间。当然,只有在本机代码和Java之间没有太多的来回时,这才是可行的。

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

附加说明:

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

  

MAP_FIXED:完全解释地址。   [...]   它是实现定义的   应支持MAP_FIXED。   应支持MAP_FIXED   符合XSI标准的系统。 [...] 什么时候   MAP_FIXED未设置,   实现使用addr   实现定义的方式   到达pa。

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

因此,即使您设法让JVM使用某个地址调用mmap,也可能仍然无法成功。

答案 1 :(得分:2)

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

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

所以,在建议这一点后,我强烈建议您不要这样做,而是按照sleske's advice并将本机代码放在一个单独的过程中。

答案 2 :(得分:1)

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