4

使用-Xms-Xmx选项,可以设置内存分配池的初始大小和最大大小。在 Linux 和 AIX 上使用strace/truss我发现,JVM 在内部使用 (k)mmap 系统调用。address -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)。该区域与 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 段中,这在标准(非大)内存模型中也可用。

4

3 回答 3

2

就个人而言,我从未听说过配置分配池地址的方法。如果有这样的设置,那估计就很不起眼了。

唯一可以确定的方法是查看 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 到达 pa。

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

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

于 2011-01-03T15:20:51.503 回答
2

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

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

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

于 2011-01-03T17:52:36.083 回答
1

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

于 2011-01-03T16:47:47.913 回答