来自JNI_CreateJavaVM的JNI_ENOMEM在调用使用VB6中的JNI的dll时

时间:2010-08-03 19:56:13

标签: java memory vb6 java-native-interface visio

我在遗留系统上工作,该系统具有需要调用Java代码的VB6应用程序。我们使用的解决方案是让VB应用程序调用C ++ DLL,它使用JNI来调用Java代码。有点时髦,但实际上效果很好。但是,我正在转向一个新的开发盒,我刚刚遇到了一个严重的问题。构建的VB应用程序在新框中运行正常,但是当我尝试从VB运行它时,dll无法加载VM,从JNI_CreateJavaVM获取返回代码-4(JNI_ENOMEM)。

构建的应用程序和VB都调用完全相同的dll,我已经尝试使用Java 1.5和1.6。我已经尝试了建议here(将stdout和stderr重定向到文件,添加vfprint选项,添加-Xcheck:jni选项),但无济于事。我似乎无法从jvm中获取任何其他信息。据我所知,新的盒子配置与旧盒子(安装的软件,路径,类路径等)几乎相同,并且两者都运行相同版本的Windows Server 2003.新机器是x64具有更多内存的盒子(4GB而不是2GB),但它运行的是32位Windows。

关于还有什么可以研究的任何建议或想法?以更合理的方式重写整个事情不是一个选择 - 我需要找到一种方法让dll加载jvm而不用认为它是内存不足。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

好的,我已经明白了。正如kschneid指出的那样,JVM在应用程序的内存空间中需要一个相当大的连续内存块。所以我使用sysinternals VMMap实用程序来查看VB的内存是什么样的。事实上,没有大块可用的内存,并且有一些属于Visio的库被设置为破坏内存的位置。事实证明,当我在新机器上安装Visio时,它会自动将Visio UML插件安装到VB中。由于我不使用此加载项,因此我将其禁用。禁用加载项后,可用的内存空间很大,现在JVM加载得很好。

答案 1 :(得分:1)

仅供参考 - 我找到了以下非常有用的文章:https://forums.oracle.com/forums/thread.jspa?messageID=6463655

我将在这里重复一些非常有用的代码,因为我不确定我是否相信Oracle会保留上述论坛。

当我设置我的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;
}

答案 2 :(得分: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”。它解决了我的问题,但由于这种变化,我可能会产生副作用。