2010-08-03 3 views
1

Je travaille sur un système hérité qui a une application VB6 qui doit appeler du code Java. La solution que nous utilisons est que l'application VB appelle une DLL C++ qui utilise JNI pour appeler le code Java. Un peu génial, mais ça fonctionne plutôt bien. Cependant, je passe à une nouvelle boîte de dev, et je viens de rencontrer un sérieux problème avec cela. L'application VB intégrée fonctionne correctement sur la nouvelle boîte, mais lorsque j'essaie de l'exécuter à partir de VB, la DLL ne parvient pas à charger la machine virtuelle, obtenant un code retour de -4 (JNI_ENOMEM) à partir de JNI_CreateJavaVM.JNI_ENOMEM de JNI_CreateJavaVM lors de l'appel d'une DLL utilisant JNI à partir de VB6

L'application construite et VB appellent exactement la même DLL, et je l'ai essayé avec Java 1.5 et 1.6. J'ai essayé les suggestions here (en redirigeant stdout et stderr vers des fichiers, en ajoutant une option vfprint, en ajoutant une option -Xcheck: jni), mais en vain. Je n'arrive pas à obtenir des informations supplémentaires sur le jvm. Pour autant que je sache, la nouvelle boîte est configurée à peu près la même que l'ancienne (logiciel installé, Path, Classpath, etc.), et les deux exécutent la même version de Windows Server 2003. La nouvelle machine est un x64 boîte avec plus de mémoire (4 Go plutôt que 2 Go), mais il fonctionne sous Windows 32 bits.

Avez-vous des suggestions ou des idées sur quoi regarder? Réécrire le tout d'une manière plus saine n'est pas une option - j'ai besoin de trouver un moyen de faire en sorte que la dll charge la jvm sans penser que c'est trop loin de la mémoire. Toute aide serait très appréciée.

+0

Est-ce que vous passez des options à la JVM pour définir la taille maximale du segment de mémoire et/ou de la perm max? La somme de ces deux tailles doit être disponible en tant que bloc contigu pour que la JVM puisse démarrer. – kschneid

+0

À l'origine, nous utilisions simplement les valeurs par défaut (juste en passant un chemin de classe). J'ai essayé de passer différentes valeurs pour -Xmx et -Xms. Jusqu'à 52 m, l'appel dll a simplement provoqué la fermeture de VB (sans message d'erreur). A partir de 53m, j'obtiens le code de retour JNI_ENOMEM.Il y a certainement beaucoup de mémoire disponible, et à moins que VB ne fasse quelque chose de vraiment bizarre avec l'allocation de mémoire pour les DLL, il devrait y avoir assez de mémoire contiguë disponible pour une JVM avec un tas de 53 Mo. Et tout cela fonctionne très bien sur ma vieille boîte de dev (et sur toutes les autres machines que nous avons utilisées). –

Répondre

1

OK, je l'ai compris. Comme le souligne kschneid, la JVM a besoin d'un gros morceau de mémoire contigu à l'intérieur de l'espace mémoire de l'application. J'ai donc utilisé l'utilitaire sysinternals VMMap pour voir à quoi ressemblait la mémoire de VB. Il n'y avait, en fait, pas beaucoup de mémoire disponible, et il y avait quelques bibliothèques appartenant à Visio qui étaient chargées dans des endroits qui semblaient conçus pour fragmenter la mémoire. Il s'avère que lorsque j'ai installé Visio sur la nouvelle machine, il a automatiquement installé le complément Visio UML dans VB. Comme je n'utilise pas ce complément, je l'ai désactivé. Avec le complément désactivé, il y avait un gros morceau contigu de mémoire disponible, et maintenant la JVM se charge très bien.

0

J'ai eu le même problème décrit par "le klaus" et lu "http://support.microsoft.com/kb/126962". Changé le registre comme décrit dans l'article mentionné. J'ai exagère ma modification à: "% SystemRoot% \ system32 \ csrss.exe ObjectDirectory = \ Windows SharedSection = 3072,3072,3072 Windows = Sur SubSystemType = Windows ServerDll = basesrv, 1 ServerDll = winsrv: UserServerDllInitialization, 3 ServerDll = winsrv: ConServerDllInitialization , 2 ProfileControl = Off MaxRequestThreads = 16 "

Le champ à consulter est" SharedSection = 3072,3072,3072 ". Cela a résolu mon problème, mais j'ai peut-être des effets secondaires à cause de ce changement.

+0

Cela ne ressemble pas vraiment au même problème. La cause du problème pour cette question est l'espace d'adressage de processus fragmenté, pas à court d'espace de tas de bureau WIN32. – kschneid

1

FYI - J'ai trouvé l'article suivant extrêmement utile: https://forums.oracle.com/forums/thread.jspa?messageID=6463655

Je vais répéter un code utile ici parce que follement je ne suis pas sûr que je fais confiance Oracle pour garder dans le forum ci-dessus. Lorsque j'installe ma JVM, j'utilise un appel à getMaxHeapAvailable(), puis définissez mon espace de tas en conséquence (-Xmxm) - fonctionne bien pour les stations de travail avec moins de RAM disponible, sans avoir à pénaliser les utilisateurs avec de grandes quantités de 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; 
} 
Questions connexes