java 32位窗口:确定启动JRE时可用的最大堆

时间:2014-11-02 19:54:13

标签: java memory launch4j

我们的Java应用程序(我们希望与32位Windows计算机保持兼容,因此使用32位JRE)是内存密集型的,我们希望在启动JRE时使用Xmx参数为其提供最大可用内存。

虽然理论上32位提供4Gb的可分配内存,但我们知道,鉴于Windows的内存管理,它受到可用内存最大连续内存的限制。一些测试表明,大多数计算机上最有可能使用1024mb的值。

我们现在正在研究最佳方法来分配启动应用程序时可用的最大堆内存:除了试错之外是否有任何方法(即启动4GB的JRE,然后减少直到它工作)?

另外,我们使用Launch4J启动我们的应用程序:这会提供额外的选项来定义可能的最大堆内存吗?

1 个答案:

答案 0 :(得分: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;
}