Windows上每个Java进程的最大内存限制是多少?

24

在32位Windows上,使用-Xmx为Java进程分配的最大堆大小是多少?

我之所以问这个问题,是因为我想在OpenMap中使用ETOPO1数据,而原始二进制浮点文件约为910 MB。


1
看起来是 https://dev59.com/M3VC5IYBdhLWcg3w1E1q 的副本。 - Michael Myers
2
我应该停止依赖问题提问者的搜索。 - Jay R.
请参阅 http://wiki.eclipse.org/Eclipse.ini 和 http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html#generation_sizing,了解有关编程的相关信息。 - Andrew
5个回答

45
进行实证试验是回答你的问题的最好方法之一。 我编写了一个Java程序,并在运行时指定了XMX标志(也使用XMS = XMX强制JVM预分配所有内存)。 为了进一步防止JVM优化,我积极分配了X个10MB对象。 我在许多JVM上运行了一些测试,逐步增加了分配的MB数量以及增加32位操作系统,使用Sun和IBM JVM,以下是结果摘要:
Windows XP SP2, JVM:Sun 1.6.0_02,最大堆大小:1470 MB Windows XP SP2,JVM:IBM 1.5,最大堆大小:1810 MB Windows Server 2003 SE,JVM:IBM 1.5,最大堆大小:1850 MB Linux 2.6,JVM:IBM 1.5,最大堆大小:2750 MB
以下是详细的运行尝试和分配类帮助程序源代码:

import java.util.StringTokenizer;


public class Class1 {

        public Class1() {}

        private class BigObject {
                byte _myArr[];
                public BigObject() {
                        _myArr = new byte[10000000];
                }
        }
    public static void main(String[] args) {
                (new Class1()).perform(Integer.parseInt(args[0]));
        }
        public void perform(int numOfObjects) {
                System.out.println("creating 10 MB arrays.");
                BigObject arr[]  = new BigObject[numOfObjects];
                for (int i=0;i <numOfObjects; i++) {
                        System.out.println("about to create object "+i);
                        arr[i] = new BigObject();
                        System.out.println("object "+i+" created");
                }
                System.out.println("sleeping for 5 seconds.");
                try {
                Thread.sleep(5000);
                }catch (Exception e) {e.printStackTrace();}
                System.out.println("Done.");
    }

}

我假设您在此测试中已经使用了32位操作系统的最大内存容量。 - Jay R.
1
就像你所说的那样。对于Windows 7 64位和Sun JDK 6更新27 32位,最大堆大小为1220 MB;尽管计算机有6GB RAM。 - Mohamed ElNakeep

4

对于大文件,建议使用内存映射文件。这不会使用堆空间(或者很少),因此在这种情况下最大堆大小不应该是一个问题。


3
我们最近从Windows迁移到Linux(因为VM大小问题)。
我之前听说过很多关于Windows VM大小的数字(1200、1400、1600、1800),但在我们的环境下,使用我们的应用程序,在我们的Windows服务器(2003)上,我从未成功使用超过1280MB。超过这个值,我们的应用程序就开始出现GC和OOM问题。
每次我得到一个新的VM版本,我都试图改变这个数字,但它从未变化过。
现在你有一个900MB的文件,如果文件增加到1300MB会怎么办?
你有几个选择:
1.迁移到Linux/Solaris。这只需要硬件/软件以及通常是简单的移植练习。
2.使用64位Windows。虽然可能不免费遇到GC问题,但我听说过64位虚拟机有不同的故事。
3.重新设计应用程序以不同的方式处理文件,例如:逻辑上分割文件,分块读取文件并以不同的方式处理等。
其他使用OpenMap的人必须也遇到了这个问题。你可以利用他们的知识而不必重新发明轮子。

我只是需要一个短期的演示,所以最好只读取我需要的部分,并根据缩放级别将显示从ETOPO1降级到5或10。 - Jay R.

2

如评论中提到的问题所述,实际上存在一个实际限制,大约为1200 MB。

然而,您所描述的情况比纯粹的内存大小更为深入。

当您读取910 MB的二进制数据并基于它构建网络对象(而不仅仅将数据保留为字节数组)时,您最终会消耗比910 MB多得多的内存。合理的估计是,内存中的表示将消耗两倍的内存 - 这是因为(1)每个对象都包含一个额外的指针(指向对象的类);和(2)有很多簿记数据。例如,如果您使用HashMap来管理对象,则除了每个对象之外,还会分配一个Map.Entry对象,该对象可以轻松消耗16或20字节(具体实现取决于)。

另一方面,仍然有希望:您真的需要在内存中保留所有910 MB吗?不能您只构建以懒惰方式读取数据的东西吗?结合WeakReferences,我认为您可以做到这一点。


实际上,它被存储为一个大的浮点数数组。 - Jay R.

-2
在32位Windows系统中,默认情况下,每个应用程序可以使用高达2GB的虚拟地址空间。我猜这就是-Xmx2048M。然而,如果你安装了更多内存,你可以通过使用启动参数将虚拟地址空间增加到3GB。
在boot.ini中,你可以创建一个新的启动选项,如下所示:
[boot loader]<br>
timeout=5<br>
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS<br>
[operating systems]<br>
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional - magyar" /noexecute=optin /fastdetect /usepmtimer<br>
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional - magyar 3GB" /noexecute=optin /fastdetect /usepmtimer /3GB /USERVA=2800<br>

通过调整/USERVA=2800参数,您可以优化您的机器。但请注意,某些配置不喜欢这个参数的高值 - 可能会导致崩溃。


1
你实际上不能在Java进程中将所有的内存都分配给堆。我曾经成功地分配了最多1400M的内存,而且这只是在一台机器上实现的 - 我无法在其他任何地方重复这个记录! - Bill Michell
我在Vista上成功分配了1500M。我没有尝试1500M和1600M之间的任何值,但1600M无法工作。 - Jay R.
现在我也尝试了一下。在我的机器上,有2GB的内存和1400MB的空闲空间时,只有当我指定-Xmx1400M时JVM才能运行,否则会出现“无法为对象堆保留足够的空间”的错误。 - akarnokd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接