从 VB6 调用使用 JNI 的 dll 时,来自 JNI_CreateJavaVM 的 JNI_ENOMEM

发布于 2024-09-12 12:28:11 字数 730 浏览 5 评论 0原文

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

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

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

I work on a legacy system that has a VB6 app that needs to call Java code. The solution we use is to have the VB app call a C++ dll that uses JNI to call the Java code. A bit funky, but it's actually worked pretty well. However, I'm moving to a new dev box, and I've just run into a serious problem with this. The built VB app works fine on the new box, but when I try to run it from VB, the dll fails to load the VM, getting a return code of -4 (JNI_ENOMEM) from JNI_CreateJavaVM.

Both the built app and VB are calling the exact same dll, and I've tried it with both Java 1.5 and 1.6. I've tried the suggestions here (redirecting stdout and stderr to files, adding a vfprint option, adding an -Xcheck:jni option), but to no avail. I can't seem to get any additional information out of the jvm. As far as I can tell, the new box is configured pretty much the same as the old one (installed software, Path, Classpath, etc.), and both are running the same release of Windows Server 2003. The new machine is an x64 box with more memory (4GB rather than 2GB), but it's running 32-bit Windows.

Any suggestions or ideas about what else to look into? Rewriting the whole thing in a more sane way is not an option -- I need to find a way to have the dll get the jvm to load without thinking that it's out of memory. Any help would be much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

转瞬即逝 2024-09-19 12:28:11

好吧,我已经弄清楚了。正如 kschneid 指出的,JVM 在应用程序的内存空间中需要相当大的连续内存块。因此,我使用 sysinternals VMMap 实用程序来查看 VB 的内存情况。事实上,没有大块可用内存,并且有一些属于 Visio 的库被加载到似乎被设计为碎片内存的位置。事实证明,当我在新机器上安装 Visio 时,它自动将 Visio UML 插件安装到 VB 中。由于我不使用此加载项,因此我将其禁用。禁用该加载项后,有大量连续的可用内存,现在 JVM 加载得很好。

OK, I've figured it out. As kschneid points out, the JVM needs a pretty large contiguous chunk of memory inside the application's memory space. So I used the sysinternals VMMap utility to see what VB's memory looked like. There was, in fact, no large chunk of memory available, and there were some libraries belonging to Visio that were loadeed in locations that seemed to be designed to fragment memory. It turns out that when I installed Visio on the new machine, it automatically installed the Visio UML add-in into VB. Since I don't use this add-in, I disabled it. With the add-in disabled, there was a large contiguous chunk of free memory available, and now the JVM loads just fine.

﹎☆浅夏丿初晴 2024-09-19 12:28:11

仅供参考 - 我发现以下非常有用的文章: 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;
}

FYI - I found the following extremely useful article: https://forums.oracle.com/forums/thread.jspa?messageID=6463655

I'm going to repeat some insanely useful code here because I'm not sure that I trust Oracle to keep the above forum around.

When I set up my JVM, I use a call to getMaxHeapAvailable(), then set my heap space accordingly (-Xmxm) - works great for workstations with less RAM available, without having to penalize users with large amounts of 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;
}
淑女气质 2024-09-19 12:28:11

我遇到了“the klaus”描述的相同问题并阅读了“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”。它解决了我的问题,但由于这种变化我可能会产生副作用。

I had the same problem described by "the klaus" and read "http://support.microsoft.com/kb/126962". Changed the registry as described in the mentioned article. I exagerated my change to : "%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"

The field to look at is "SharedSection=3072,3072,3072". It solved my problem, but I may have side-effects because of this change.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文