【问题标题】:Java 32 bit memory threshold on 64 bit Windows 1064 位 Windows 10 上的 Java 32 位内存阈值
【发布时间】:2018-04-30 15:32:40
【问题描述】:

我有一些软件需要大约 1500m 的内存才能正常运行。我在开始时使用 xms 和 xmlx 强制此数量,以确保它具有所需的内存。我曾经在 Windows XP 或 Windows 7 上运行它并且运行良好。切换到 Windows 10 后,我突然发现我没有足够的内存来运行它了。在研究了 Java 中的内存是如何工作的之后,我在此页面上发现了以下信息:

http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#gc_heap_32bit

由于各种额外的限制,例如可用交换、内核地址空间使用、内存碎片和 VM 开销,实际上限制可以低得多。在大多数现代 32 位 Windows 系统上,最大堆大小范围为 1.4G 到 1.6G。

听起来我一直处于 32 位 Java 能力的边缘。测试我的机器的极限,似乎我目前的最大值约为 1.1g。目前切换到 64 位可能不在桌面上,所以我试图弄清楚如何恢复我从最大内存阈值中丢失的大约 0.5g。我已尝试研究常见问题解答中列出的所有可能影响它的内容。

  • 可用交换:这似乎是页面文件或虚拟内存。显然增加这个有时会有所帮助。有时当我增加此值时,我会在重启后看到暂时的改善,但如果我再次重启,修复似乎永远不会持续。

  • 内核地址空间使用:这似乎是操作系统的内存上限。我们不能做任何改变吗?

  • 内存碎片:据说 Windows 10 实际上比以前版本的 Windows 更擅长处理这个问题。所以这不应该是一个因素。

  • VM 开销:似乎是指其他虚拟机的 RAM 使用情况。除了 Java,我认为我没有运行任何其他可以算作虚拟机的东西。

是否有任何可靠的方法来识别和纠正可能导致 Windows 版本之间性能差异的原因?这非常令人沮丧,因为我现在拥有的物理内存比以往任何时候都多,但唯一重要的 RAM 是允许使用的 RAM JVM,而现在不知何故更少了。

更新

我听到了。我知道我可以轻松修复它,切换到 64 位;我的问题是如何在不这样做的情况下修复它。出于学术原因和实际原因,了解 JVM 如何确定它的最大堆不是很有帮助吗?我怀疑有很多应用程序达到了 64 位 Java 的上限,但如果有的话,Java 的行为方式不一样吗?

【问题讨论】:

  • 是否有任何正当理由使用 32 位版本的 Windows?你真的在硬件上运行,以至于无法支持 64 位 Windows?
  • “VM 开销”不是指其他虚拟机的 RAM 使用情况。它指的是您正在运行的 VM 所需的内存,用于它自己的内部需求。
  • “有什么正当理由不使用它?” 单个进程(例如 VM)的内存空间不足。对我来说似乎是一个非常正当的理由。
  • 在 32 位 Windows 上,每个进程的地址空间受架构限制为 4GB。考虑到必要的开销,包括 JVM 本身,最大值始终在 1 到 1.5 GB 之间。 (顺便说一句,交换与此无关)。如果 WinX 下的可用空间大于 Win7 下的可用空间,我会感到非常惊讶。您可能会在今天硬塞它,但您距离再次触顶的 Windows 更新只有一个。是时候淘汰旧笔记本并转向更现代的东西了。
  • @JimGarrison 我正在运行 64 位 Windows,它是 32 位的 java。

标签: java performance memory memory-management out-of-memory


【解决方案1】:

我无法弄清楚为什么系统之间的内存不同,但我确实了解到我可以在 Java.exe 上设置一个 LARGEADDRESSAWARE 标志,这将允许它拥有多达 1G 的内存。

在人们通常用来设置标志的几种工具中,我发现了这个自定义编码的 python 脚本,它试图在你手头的任何 .exe 文件上设置它。使用它,我可以将 Java.exe 提供给它,现在一切正常。

似乎通常不建议设置此标志,但到目前为止没有副作用。我会一直使用它,直到我能正确地将所有东西都切换到 64 位。

https://github.com/pyinstaller/pyinstaller/issues/1288

# See http://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#PE_Header
# and https://msdn.microsoft.com/en-us/library/ms680349%28v=vs.85%29.aspx

import struct

IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020
PE_HEADER_OFFSET = 60
CHARACTERISTICS_OFFSET = 18

def set_large_address_aware(filename):
    f = open(filename, 'rb+')
    # Check for MZ Header
    if f.read(2) != b'MZ':
        print('Not MZ')
        return False
    # Get PE header location
    f.seek(PE_HEADER_OFFSET)
    pe_header_loc, = struct.unpack('i', f.read(4))
    # Get PE header, check it
    f.seek(pe_header_loc)
    if f.read(4) != b'PE\0\0':
        print('error in PE header')
        return False
    # Get Characteristics, check if IMAGE_FILE_LARGE_ADDRESS_AWARE bit is set
    charac_offset = pe_header_loc + 4 + CHARACTERISTICS_OFFSET
    f.seek(charac_offset)
    bits, = struct.unpack('h', f.read(2))
    if (bits & IMAGE_FILE_LARGE_ADDRESS_AWARE) == IMAGE_FILE_LARGE_ADDRESS_AWARE:
        return True
    else:
        print('large_address_aware is NOT set - will try to set')
        f.seek(charac_offset)
        bytes = struct.pack('h', (bits | IMAGE_FILE_LARGE_ADDRESS_AWARE))
        f.write(bytes)
    f.close()
    return False

if set_large_address_aware('file.exe'):
    print('large_address_aware is set')
else:
    print('large_address_aware was NOT set')

【讨论】:

  • 所以这“解决”了问题?
  • @rogerdpack 似乎是一种解决方法,也被其他人使用,并解决了 OP 的直接困难。
  • @rogerdpack 之类的。显然,没有人了解 Java 的最大堆是如何确定的细节。或者至少没有一种简单的方法可以做到这一点。我能找到的最佳解决方案是为 Java 提供更多内存以供使用,并希望它不会浪费它。
  • 另见这个较早的讨论(2010 年时间框架)Drawbacks of using /LARGEADDRESSAWARE for 32 bit Windows executables? 虽然这可能适用于也可能不适用于 Windows 10 或 64 位 Windows。
猜你喜欢
  • 2011-09-02
  • 2018-01-25
  • 2012-10-26
  • 2011-03-10
  • 1970-01-01
  • 1970-01-01
  • 2018-01-29
  • 2011-10-26
  • 1970-01-01
相关资源
最近更新 更多