有没有办法强制JVM使用swap,无论内存需求有多大?

时间:2011-01-03 11:20:39

标签: java memory jvm

这是我的情况:我手头有一项需要大量记忆的任务。我没有足够的ram,无论我尝试了什么(Jrockit和/ 3gb交换机等),我都不能给JVM足够的ram并且操作以异常终止,告诉我需要更多的堆空间。

有什么方法可以强制JVM使用操作系统的交换机制,这样它就不会耗尽内存?这是Windows xp 32位

这需要很长时间,但我不在乎,我只需要完成此操作。

我的选项用完了,而且我无法控制任何变量..

这是必需的编辑,因为我几乎所有人都有相同的回复:) 这不是我的代码。有人编写了一个将xml文件读入存储库的工具。该工具使用EMF,并立即加载整个模型。我所能做的就是为它提供XML文件。 如果本机代码在Windows或Linux等下运行,操作系统会使用虚拟内存/交换空间为其提供内存,而应用程序并不知道它。 我想知道是否可以对JVM做同样的事情。在Windows 32位下,-Xmx可以达到一定数量,但这还不够。 出门购买新硬件暂时不适合我。所以我想知道是否有可能使JVM像本机进程一样工作。慢,但仍在工作。 显然这是不可能的,我运气不好。我只需要知道我是否真的没有选择。

4 个答案:

答案 0 :(得分:10)

显然,Java堆的限制有一种方法。它甚至被用在名为BigMemory的商业产品中,它基本上允许您通过透明地交换到OS交换和/或磁盘(如果需要)来拥有几乎无限的内存。

我们的想法是使用直接ByteBuffer来存储您的对象数据。因为直接字节缓冲区的内容存储在本机进程内存中(而不是堆),所以可以依靠操作系统交换机制为您交换内存。我在this website上找到了这个(在页面上搜索“直接字节缓冲区”)。

以下是如何实现它(java-pseudo-code'ish):

class NativeMemoryCache{
  private Map<Object, ByteBuffer> data = new HashMap<...>();

  public void put(Object key, Serializable object){
    byte[] bytes = serialize(object);
    //allocate native memory to store our object
    ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
    buf.put(bytes);
    buf.flip();
    data.put(key, buf);
  }

  public Object get(Object key){
    ByteBuffer buf = data.get(key).duplicate();
    byte[] bytes = new byte[buf.remaining()];
    buf.get(bytes);
    return deserialize(bytes);
  }

  private byte[] serialize(Object obj){ ... }
  private Object deserialize(byte[] bytes){ ... }
}

希望你能得到这个想法。你只需要实现序列化(你也可以使用zip来压缩你的对象。如果你有很少的大对象,特别是包含像字符串这样的可拉伸数据的对象,这将是有效的。)

当然NativeMemoryCache对象,data哈希映射和key将在堆中,但这不应占用太多内存。

答案 1 :(得分:8)

正如其他答案所指出的,您使用-Xmx开关为JVM提供更多RAM。

然而,你可以走多远是有限度的。在32位系统上,如果JVM支持它,它可能是2GiB,可能是3或4 GiB。根据{{​​3}},对于Sun JVM,32位Windows上的限制为1500MiB。

出于基本体系结构的原因,进程不能(没有特殊技术)获得超过4 GiB的内存(包括它可能使用的任何交换空间),这就是-Xmx的限制的原因价值存在。

如果您尝试了最大可能值,但仍然会出现OOM错误,那么您唯一的选择是:

  • 修复应用程序,使其需要更少的RAM

  • 将其移至64位操作系统,并进一步增加-Xmx

编辑:

请注意,4 GiB限制是 CPU体系结构的限制,因此它适用于任何进程,无论是否为Java。因此,即使是原生分配技巧也无法帮到你。唯一的解决方法是使用多个进程,但这需要对应用程序进行基本的重写,这可能就像修复应用程序以减少RAM一样复杂。所以上面两个选项是你唯一的(明智的)选择。

编辑2:

要解决问题的新部分:

  

我想知道是否有可能   使JVM像本机一样工作   过程

这是一种误解。在这方面,JVM 就像本机进程一样工作:它使用的堆位于JVM从OS分配的内存中;对于操作系统来说,这只是分配了内存,操作系统会像任何其他内存一样将其交换出来 - 如果感觉就好 - 没有什么特别之处。

堆无法无限增长的原因并不是它不能大于物理RAM(它可以,我至少在Linux / x86上尝试过),但每个操作系统进程(JVM都是)无法获得超过4GiB RAM。所以在32位系统上,你永远不会有超过4GiB的堆。在实践中,它可能要少得多,因为堆内存不能被分段(参见例如Java -Xmx, Max memory on system),但4GiB是一个很难的,不可避免的限制。

答案 2 :(得分:3)

根据我的经验,JVM从OS请求内存,可以在交换机的RAM中分配它。这取决于你有多少资源。您可以在java中分配的内存不依赖于您的RAM,而是依赖于您在运行JVM时指定的命令行选项-Xmx。例如,如果RAM中没有足够的内存,JVM会从交换中接收它(我相信)甚至不知道。

BTW恕我直言,你不真的需要这么多内存。我同意那些说过的人。我建议你检查你的设计。

答案 3 :(得分:0)

如果没有足够的RAM,则需要更改代码,以便应用程序适合内存。如果你使JVM足够大,它必须交换到磁盘应用程序,它就像挂起一样好。 JVM中的堆不是为了在磁盘上运行而设计的。

我怀疑你遇到的问题是你无法分配足够的连续内存,这是JVM的要求。当您使用更多可用内存时,使用32位操作系统获取大型连续内存块会更加困难。

现在是获得更多内存的时候了,这些日子相对便宜。或减少你的记忆要求。使用swap只需要永远完成。

BTW:您可以以大约£1,800和64 GB服务器购买24 GB服务器,价格约为4,200英镑。对于53,000英镑,您可以获得1 TB内存的服务器! :d