2014-11-02 36 views
0

我们的Java应用程序(即我们希望与32位Windows计算机保持兼容,因此使用32位JRE)是内存密集型的,我们希望给它启动JRE时使用的最大可用内存(使用Xmx参数)。java 32位窗口:确定启动JRE时可用的最大堆栈

尽管理论上32位给出了4Gb的可分配内存,但我们明白,给定Windows的内存管理,它会受到最大连续可用内存块的限制。一些测试表明,在大多数计算机上最有可能使用1024mb的值。

现在我们正在进入最好的办法来分配可用的最大堆内存启动应用程序时:是不是有试错之外的任何方法(即拥有4GB推出JRE,然后下降,直到它的工作原理) ?另外,我们使用Launch4J启动我们的应用程序:这是否会提供额外的选项来定义可能的最大堆内存?

+0

32位给你2GiB。唯一的分配方式是编写一个脚本,它试图通过'-Xmx'分配不同的数量,如果进程退出并返回错误代码,则继续执行。请记住,如果您分配最大内存,操作系统将耗尽您不想要的虚拟内存。请注意:可用于分配的最大内存取决于最大连续的虚拟内存块。 – bestsss 2014-11-02 20:34:42

+0

还有一点需要注意:你不希望java使用swap,完全垃圾回收会影响swap,可能会花费几分钟。 – bestsss 2014-11-02 20:41:14

+0

谢谢。有没有办法使用Launch4J来编写试验脚本,或者至少检测是否存在内存问题并显示优雅的错误消息? – Tom 2014-11-02 20:41:18

回答

0

下面是我在我们基于JNI的发射器中使用的win32代码 - 这种方法的原始灵感是一个我不再能够找到的网站 - 希望它可以使用(我不知道是否Launch4J有这样的事情 - 如果他们不这样做,你应该要求他们添加它;-))。我使用62作为permGenMB。 maxHeapMB是要请求的最大大小(768,1024) - getMaxHeapAvailable()函数将返回机器实际为您分配的限制以下的大小。

请注意,win32具有大约3GB的可寻址内存,但您无法获得大块--JVM要求内存位于单个可分配块中 - 您的计算机可能具有5GB的RAM,但如果最大的开放块只有1GB,那么这就是JVM可以获得的最大值。

static const DWORD NUM_BYTES_PER_MB = 1024 * 1024; 

bool canAllocate(DWORD bytes) 
{ 
    LPVOID lpvBase; 

    lpvBase = VirtualAlloc(NULL, bytes, MEM_RESERVE, PAGE_READWRITE); 
    if (lpvBase == NULL) return false; 

    VirtualFree(lpvBase, 0, MEM_RELEASE); 

    return true; 
} 

int getMaxHeapAvailable(int permGenMB, int maxHeapMB) 
{ 
    DWORD  originalMaxHeapBytes = 0; 
    DWORD  maxHeapBytes = 0; 
    int   numMemChunks = 0; 
    SYSTEM_INFO  sSysInfo; 
    DWORD  maxPermBytes = permGenMB * NUM_BYTES_PER_MB;  // Perm space is in addition to the heap size 
    DWORD  numBytesNeeded = 0; 

    GetSystemInfo(&sSysInfo); 

    // jvm aligns as follows: 
    // quoted from size_t GenCollectorPolicy::compute_max_alignment() of jdk 7 hotspot code: 
    //  The card marking array and the offset arrays for old generations are 
    //  committed in os pages as well. Make sure they are entirely full (to 
    //  avoid partial page problems), e.g. if 512 bytes heap corresponds to 1 
    //  byte entry and the os page size is 4096, the maximum heap size should 
    //  be 512*4096 = 2MB aligned. 

    // card_size computation from CardTableModRefBS::SomePublicConstants of jdk 7 hotspot code 
    int card_shift = 9; 
    int card_size = 1 << card_shift; 

    DWORD alignmentBytes = sSysInfo.dwPageSize * card_size; 

    maxHeapBytes = maxHeapMB * NUM_BYTES_PER_MB + 50*NUM_BYTES_PER_MB; // 50 is an overhead fudge factory per https://forums.oracle.com/forums/thread.jspa?messageID=6463655 (they had 28, I'm bumping it 'just in case') 

    // make it fit in the alignment structure 
    maxHeapBytes = maxHeapBytes + (maxHeapBytes % alignmentBytes); 
    numMemChunks = maxHeapBytes/alignmentBytes; 
    originalMaxHeapBytes = maxHeapBytes; 

    // loop and decrement requested amount by one chunk 
    // until the available amount is found 
    numBytesNeeded = maxHeapBytes + maxPermBytes; 
    while (!canAllocate(numBytesNeeded) && numMemChunks > 0) 
    { 
     numMemChunks --; 
     maxHeapBytes = numMemChunks * alignmentBytes; 
     numBytesNeeded = maxHeapBytes + maxPermBytes; 
    } 

    if (numMemChunks == 0) return 0; 

    // we can allocate the requested size, return it now 
    if (maxHeapBytes == originalMaxHeapBytes) return maxHeapMB; 

    // calculate the new MaxHeapSize in megabytes 
    return maxHeapBytes/NUM_BYTES_PER_MB; 
}