2010-08-03 28 views
1

我在具有需要調用Java代碼的VB6應用程序的舊系統上工作。我們使用的解決方案是讓VB應用程序調用一個使用JNI調用Java代碼的C++ dll。有點時髦,但它實際上工作得很好。不過,我正在轉向一個新的開發箱,而我剛剛遇到了一個嚴重的問題。構建的VB應用程序在新框中工作正常,但是當我嘗試從VB運行它時,DLL無法加載虛擬機,從JNI_CreateJavaVM獲取-4(JNI_ENOMEM)的返回代碼。從JNI_CreateJavaVM調用使用來自VB6的JNI的dll時的JNI_ENOMEM

構建的應用程序和VB都調用完全相同的DLL,我已經用Java 1.5和1.6來試用它。我已經嘗試了建議here(將stdout和stderr重定向到文件,添加vfprint選項,添加-Xcheck:jni選項),但無濟於事。我似乎無法從jvm中獲得任何其他信息。據我所知,新盒子的配置與舊盒子(安裝的軟件,Path,Classpath等)幾乎相同,並且都運行相同版本的Windows Server 2003.新機器是x64 (4GB而不是2GB),但它運行的是32位Windows。

任何關於還有什麼建議的建議或想法?以一種更爲理智的方式重寫整個事情不是一種選擇 - 我需要找到一種方法讓dll獲取jvm,而不會想到內存不足。任何幫助將非常感激。

+0

您是否將任何選項傳遞給JVM以設置最大堆和/或最大燙髮大小?這兩種尺寸的總和需要作爲JVM啓動的連續塊使用。 – kschneid 2010-08-04 03:00:14

+0

最初,我們只是使用默認值(只是傳遞一個類路徑)。我嘗試傳遞-Xmx和-Xms的各種值。高達52米,dll調用只是導致VB退出(沒有錯誤消息)。從53米起,我得到了JNI_ENOMEM返回碼。當然有足夠的內存可用,除非VB爲dll的內存分配做了一些非常奇怪的事情,那麼應該有足夠的連續內存用於具有53MB堆的JVM。而這一切在我的舊開發盒(以及我們使用過的所有其他機器上)上都可以正常工作。 – 2010-08-04 10:40:29

回答

1

好的,我已經想通了。正如kschneid所指出的那樣,JVM需要在應用程序內存空間內有相當大的連續內存塊。所以我使用sysinternals VMMap工具來查看VB的內存是什麼樣的。事實上,沒有大量的內存可用,並且有一些屬於Visio的庫被放置在似乎被設計用於分割內存的位置。事實證明,當我在新機器上安裝Visio時,它會自動將Visio UML加載項安裝到VB中。由於我不使用這個加載項,所以我禁用了它。在加載項被禁用的情況下,有大量連續的可用內存塊,現在JVM加載得很好。

0

我遇到了「克勞斯」所描述的相同問題,並且讀了「http://support.microsoft.com/kb/126962」。按照上述文章中的描述更改了註冊表。我將我的更改提升爲:「%SystemRoot%\ system32 \ csrss.exe ObjectDirectory = \ Windows SharedSection = 3072,3072,3072 Windows = On SubSystemType = Windows ServerDll = basesrv,1 ServerDll = winsrv:UserServerDllInitialization,3 ServerDll = winsrv:ConServerDllInitialization ,2 ProfileControl = Off MaxRequestThreads = 16「

要查看的字段是」SharedSection = 3072,3072,3072「。它解決了我的問題,但由於這種變化,我可能會有副作用。

+0

這看起來不像是同一個問題。此問題的原因是零碎的進程地址空間,而不是用完WIN32桌面堆空間。 – kschneid 2010-08-06 14:49:02

1

僅供參考 - 我發現下面的非常有用的文章:https://forums.oracle.com/forums/thread.jspa?messageID=6463655

我要在這裏重複一些瘋狂有用的代碼,因爲我不知道,我相信甲骨文保持上述論壇圍繞。

當我設置我的JVM時,我使用調用getMaxHeapAvailable(),然後相應地設置我的堆空間(-Xmxm) - 適用於RAM較少的工作站,而不必懲罰具有大量RAM的用戶。

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; 

    // 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 + 50*NUM_BYTES_PER_MB) && numMemChunks > 0) // 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') 
    { 
     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; 
}