xmx machine increase java command-line virtual-memory

java - machine - ¿Obtener JVM para aumentar la demanda de memoria según sea necesario hasta el tamaño del límite de VM?



java xmx command (14)

Creo que estás fuera de suerte :-( Las opciones -Xms y -Xmx no proporcionan esa flexibilidad.

Así que creo que tendrá que envolver su invocación JVM con una secuencia de comandos que pueda determinar la cantidad máxima de memoria, y luego configurar adecuadamente -Xmx (probablemente una secuencia de comandos .vbs usando WMI en Windows). ¿O tal vez pregunta a los usuarios la primera vez que se ejecuta?

Un poco de dolor, me temo.

Enviamos una aplicación Java cuya demanda de memoria puede variar bastante dependiendo del tamaño de los datos que está procesando. Si no establece el tamaño máximo de la VM (memoria virtual), muy a menudo la JVM se cierra con una falla del GC en big data.

Lo que nos gustaría ver es que la JVM solicite más memoria, ya que GC no puede proporcionar suficiente, hasta que se agote el total de VM disponible. por ejemplo, comience con 128Mb y aumente geométricamente (o algún otro paso) cada vez que el GC fallara.

La línea de comandos JVM ("Java") permite la configuración explícita de los tamaños máximos de VM (varios comandos -Xm *), y usted pensaría que estaría diseñado para ser adecuado. Intentamos hacer esto en un archivo .cmd que enviamos con la aplicación. Pero si elige un número específico, tiene uno de los dos comportamientos incorrectos: 1) si su número es lo suficientemente pequeño como para funcionar en la mayoría de los sistemas de destino (por ejemplo, 1Gb), no es lo suficientemente grande para big data, o 2) si lo hace muy grande, la JVM se niega a ejecutarse en aquellos sistemas cuya VM real es más pequeña que la especificada.

¿Cómo se configura Java para usar la máquina virtual disponible cuando sea necesario, sin saber ese número de antemano y sin tener que cargarlo todo en el inicio?


Creo que la forma más sencilla de hacer esto sería iniciar la JVM a través de alguna aplicación de envoltura, que verificará los recursos del sistema para determinar la disponibilidad de memoria, y luego iniciar la JVM con el parámetro -Xmx apropiado.

La pregunta entonces es cómo se escribiría esa envoltura. Incluso puede ser posible que la aplicación contenedora sea una JVM, aunque no creo que la API o las propiedades del sistema expongan la información necesaria. Tal vez un script de shell o su elección podría obtener la información.


En los comentarios, usted dice que la cantidad de memoria que su aplicación realmente depende del tamaño del conjunto de datos de entrada provisto por el usuario. Esto sugiere que, en lugar de intentar capturar toda la memoria virtual disponible (lo que puede causar problemas para las otras aplicaciones del usuario), debe observar el tamaño del conjunto de datos de entrada antes de iniciar la JVM y utilizarla para calcular la cantidad de memoria que necesitará la aplicación. .

Supongamos que la máquina del usuario está configurada con una memoria física modesta y un enorme espacio de intercambio. Si inicia la JVM con un tamaño de máquina virtual enorme, podría causar graves "palizas" cuando la JVM intente acceder a los datos en páginas no residentes. Por el contrario, si le da a la JVM algo más de lo que la aplicación necesita y menos que la memoria física disponible, debería poder ejecutar cómodamente sin problemas.


Hay dos opciones en los argumentos de la máquina virtual que se pueden usar: -Xms para establecer el tamaño de la memoria al inicio y -Xmx para establecer el tamaño máximo de la memoria ...

Puede configurar una memoria de inicio baja y una máxima grande, por lo que la máquina virtual asignará nueva memoria solo si es necesario.


Leí los hilos pero no vi nada que indicara que la aplicación había sido objeto de algún tipo de perfil. Normalmente, las aplicaciones de perfil bajo ciertas condiciones para encontrar puntos calientes en el rendimiento o el uso de la memoria. Probablemente hay cosas que podrían mejorarse en la mayoría de los casos.

Si pudiera establecer los límites y entender el comportamiento de la aplicación, podría estar en condiciones de decirle a sus clientes lo que pueden o no pueden hacer con la aplicación, reduciendo así la cantidad de llamadas de soporte y dándole una mejor idea de qué mínimo o qué. Tamaño máximo de pila para enviar el producto.

Tal vez podrías comenzar con esto: http://www.eclipse.org/mat/


Los tamaños máximos de VM realmente responden a esa necesidad (establece el valor máximo, pero la VM tomará solo lo necesario, paso a paso), pero si necesita varias configuraciones, además de suministrar diferentes archivos "cmd", realmente no veo una forma (aunque buscaré un poco más)

[editar] ¿Qué hay de usar un primer programa / script (o incluso otro programa java), que verifique los recursos disponibles para el sistema, y ​​luego solo llame a su programa con el -Xm apropiado, de acuerdo con lo que se recuperó del sistema? De esa manera se adaptaría a las máquinas, incluso si no las conoces antes. Podría ser una idea ...

[Segunda edición] Ok, esto ya ha sido propuesto por skaffman , mi mal.


No creo que Sun ni IBM JVM puedan hacer esto (sé que AS / 400 puede hacerlo, pero es muy probable que no sea relevante para usted).

Yo sugeriría usar Java WebStart (y antes de descartarlo, luego se dará cuenta de que se ha actualizado con Java 6 u 10 y es mucho más adecuado para lanzar aplicaciones y applets "locales") ya que le permite proporcionar una "pequeña instancia". , "instancia más grande", "instancia gigantesca" como enlaces / íconos.

Probablemente verá las opciones "inyectar aplicación en caché de inicio de página web" y "fuera de línea".


No creo que puedas hacer lo que estás tratando de hacer; en su lugar, deberá enviar instrucciones específicas para sus clientes, sus sistemas y sus demandas de cómo pueden modificar su archivo .cmd para permitir más memoria.

Por supuesto, si su producto está dirigido a usuarios muy no técnicos, es posible que desee ocultar esto detrás de un archivo de configuración más fácil de usar. P.ej

# HIGH, MEDIUM, LOW - please change as appropriate. The guidelines are: # * HIGH - users who generate 500 items per day # * MEDIUM - 200-500 items etc memoryUsage=MEDIUM

o posiblemente implemente diferentes archivos de configuración dependiendo de la opción de producto que un usuario especifique cuando ordenen el producto en primer lugar.


Si tienes mucho tiempo en tu mano, puedes intentar lo siguiente:

Trate de obtener cuál es la memoria necesaria frente al dataset de entrada. Con esto, puede dividir el procesamiento en un conjunto diferente de clases y crear un nuevo proceso JVM para procesar los datos. Básicamente un gerente y un trabajador. El Administrador haría un análisis básico del conjunto de datos exigido y generaría un Trabajador con los requisitos de memoria apropiados. Probablemente también podría configurar a su Administrador para que esté al tanto del entorno y advertir al usuario cuando esté tratando de operar en un conjunto de datos que su máquina no puede manejar.

Esto es prácticamente una extensión de la respuesta provista por skaffman, pero ocurrirá dentro de la misma aplicación en lo que concierne al usuario.


También puedes usar la opción: -XX: + AggressiveHeap

Esto según la [documentación] [1]:

La opción -XX: + AggressiveHeap inspecciona los recursos de la máquina (tamaño de la memoria y número de procesadores) e intenta configurar varios parámetros para que sean óptimos para trabajos de larga duración que requieran mucha asignación de memoria. Originalmente estaba destinado a máquinas con grandes cantidades de memoria y una gran cantidad de CPU, pero en la plataforma J2SE, versión 1.4.1 y posteriores, se ha mostrado útil incluso en máquinas con cuatro procesadores. Con esta opción, el recolector de rendimiento (-XX: + UseParallelGC) se usa junto con el tamaño adaptativo (-XX: + UseAdaptiveSizePolicy). La memoria física en las máquinas debe tener al menos 256 MB antes de poder usar AggressiveHeap. El tamaño del montón inicial se calcula en función del tamaño de la memoria física e intenta hacer un uso máximo de la memoria física para el montón (es decir, los algoritmos intentan usar montones casi tan grandes como la memoria física total).

[1]: http://java.sun.com/docs/hotspot/gc1.4.2/#4.2.2 . AggressiveHeap | contorno


Tenemos una pequeña aplicación de C que utilizamos para lanzar todas nuestras aplicaciones Java a través de JNI. Esto nos permite:

  1. Tener un nombre de proceso significativo (especialmente importante debajo de las ventanas)
  2. Tener nuestros propios iconos (de nuevo, importante para Windows)
  3. Generar dinámicamente los classpaths (analizamos el contenido del archivo / lib para incluir automáticamente todos los archivos jar)

Para nuestras aplicaciones, simplemente codificamos el límite de almacenamiento dinámico, pero puede configurar dinámicamente el tamaño máximo de almacenamiento dinámico en función de la memoria disponible.

Este tipo de pequeña aplicación es bastante fácil de hacer (es una de las cosas más fáciles de hacer con JNI). Un buen punto de partida sería la fuente del JDK (hay una subcarpeta para java.exe que puede usar, eso es lo que hicimos). La mayoría de las personas se sorprenden al encontrar que java.exe es una aplicación pequeña (<200 líneas de código) que simplemente invoca a JNI y pasa los argumentos de la línea de comandos (heck, incluso el uso de un método llamado main () es bastante opcional una vez). empiezas a lanzar cosas tu mismo).

Aquí hay un código que no solo inicia la JVM, sino también determina el máximo espacio de almacenamiento basado en la RAM disponible de la computadora. Esto es una gran cantidad de código para una publicación SO, y no es nada bonito, pero es un código reforzado por la batalla, se ha utilizado durante casi una década en cientos de instalaciones, etc ... Disfrute:

#include <windows.h> #include <jni.h> #include <string> #include <sstream> using namespace std; #define STARTUP_CLASS "some/path/to/YourStartupClass" void vShowError(string sErrorMessage); void vShowJREError(string sErrorMessage); void vShowLastError(string sErrorMessage); void vDestroyVM(JNIEnv *env, JavaVM *jvm); void vAddOption(string& sName); string GetClassPath(string root); string GetJREPath(); int getMaxHeapAvailable(int permGenMB, int maxHeapMB); JavaVMOption* vm_options; int mctOptions = 0; int mctOptionCapacity = 0; boolean GetApplicationHome(char *buf, jint sz); typedef jint (CALLBACK *CreateJavaVM)(JavaVM **pvm, JNIEnv **penv, void *args); boolean PathExists(string &path) { DWORD dwAttr = GetFileAttributes(path.c_str()); if (dwAttr == 0xffffffff) return FALSE; else return TRUE; } // returns TRUE is there was an exception, FALSE otherwise BOOL GetExceptionString(JNIEnv* jenv, string &result) { jthrowable ex; if (NULL != (ex = jenv->ExceptionOccurred())) { // clear exception jenv->ExceptionClear(); jmethodID gmID = jenv->GetMethodID( jenv->FindClass("java/lang/Throwable"), "getMessage", "()Ljava/lang/String;"); jstring jerrStr = (jstring)jenv->CallObjectMethod(ex,gmID); // now you can look at the error message string if (jerrStr != NULL){ // make sure getMessage() didn''t return null const char *errStr = jenv->GetStringUTFChars(jerrStr,0); result = errStr; jenv->ReleaseStringUTFChars(jerrStr, errStr); } else { result = "null"; } return TRUE; } else { return FALSE; } } BOOL GetJRESystemProperty(JNIEnv *env, string propname, string &propval, string &errmessage) { // now check for minimum JRE version requirement jclass cls = env->FindClass("java/lang/System"); if (cls == NULL){ errmessage = "Unable to interact with Java Virtual Machine - please visit www.java.com and confirm that your Java installation is valid."; return FALSE; } jmethodID mid = env->GetStaticMethodID(cls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"); if (mid == NULL){ errmessage = "Unable to obtain Java runtime system properties - please visit www.java.net and confirm that your Java installation is valid."; return FALSE; } jstring propName = env->NewStringUTF( propname.c_str() ); jstring result = (jstring) env->CallStaticObjectMethod(cls, mid, propName); const char* utfResult = env->GetStringUTFChars( result, NULL ); if (utfResult == NULL){ errmessage = "Unable to obtain Java runtime system property " + propname + " - please visit www.java.net and confirm that your Java installation is valid."; return FALSE; } propval = utfResult; env->ReleaseStringUTFChars( result, utfResult ); return TRUE; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { JNIEnv *env; JavaVM *jvm; jint jintVMStartupReturnValue; jclass jclassStartup; jmethodID midStartup; // Path Determination // --- application home char home[2000]; if (!GetApplicationHome(home, sizeof(home))) { vShowError("Unable to determine application home."); return 0; } string sAppHome(home); string sOption_AppHome = "-Dapplication.home=" + sAppHome; string sJREPath = GetJREPath(); // --- VM Path string sRuntimePath = sJREPath + "//bin//client//"; // must contain jvm.dll string sJVMpath = sRuntimePath + "jvm.dll"; // --- boot path string sBootPath = sJREPath + "//lib"; string sOption_BootPath = "-Dsun.boot.class.path=" + sBootPath; // --- class path //string sClassPath = sAppHome + "//lib;" + sAppHome + "//lib//" + APP_JAR + ";" + sAppHome + "//lib//log4j-1.2.7.jar"; string cpRoot = sAppHome + "//"; string sClassPath = GetClassPath(cpRoot); string sOption_ClassPath = "-Djava.class.path=" + sClassPath; string sOption_JavaLibraryPath = "-Djava.library.path=" + sAppHome + "//lib"; int maxHeapBM = 768; int argStart = 1; // the first argument passed in that should be passed along to the JVM if(__argc > 1){ string maxheapstr = __argv[1]; if (maxheapstr.substr(0, 9).compare("/maxheap=") == 0){ maxheapstr = maxheapstr.substr(9); maxHeapBM = atoi(maxheapstr.c_str()); argStart++; } } // we now use adaptive max heap size determination - we try for 768MB of heap, but if we don''t get it, we can back off and use less instead of failing the launch // note: we had problems going for 1024 heap at TrueNorth - it would throttle back to 848 and fail with error -4 no matter what I did int maxHeapMB = getMaxHeapAvailable(62, maxHeapBM); stringstream ss; ss << "-Xmx"; ss << maxHeapMB; ss << "m"; string sOption_HeapSpace = ss.str(); string sOption_PermSize = "-XX:MaxPermSize=62m"; string sOption_HeapDump = "-XX:+HeapDumpOnOutOfMemoryError"; if (strstr(szCmdLine, "/launcher_verbose") != NULL){ string msg = "App Home = "; msg += sAppHome; msg += "/nJRE Path = "; msg += sJREPath; msg += "/nRuntime Path = "; msg += sRuntimePath; msg += "/nClass Path = "; msg += sClassPath; msg += "/nHeap argument = "; msg += sOption_HeapSpace; msg += "/nPermsize argument = "; msg += sOption_PermSize; msg += "/nHeap dump = "; msg += sOption_HeapDump; msg += "/njava.library.path = "; msg += sOption_JavaLibraryPath; msg += "/nCommand line = "; msg += szCmdLine; FILE *f = fopen("launcher.txt", "w"); fprintf(f, "%s", msg.c_str()); fclose(f); MessageBox(0, msg.c_str(), "Launcher Verbose Info", MB_OK); } // setup VM options // vAddOption(string("-verbose")); vAddOption(sOption_ClassPath); vAddOption(sOption_AppHome); vAddOption(sOption_HeapSpace); vAddOption(sOption_PermSize); vAddOption(sOption_HeapDump); vAddOption(sOption_JavaLibraryPath); // initialize args JavaVMInitArgs vm_args; vm_args.version = 0x00010002; vm_args.options = vm_options; vm_args.nOptions = mctOptions; vm_args.ignoreUnrecognized = JNI_TRUE; // need to diddle with paths to ensure that jvm can find correct libraries - see http://www.duckware.com/tech/java6msvcr71.html string sBinPath = sJREPath + "//bin"; char originalCurrentDirectory[4096]; GetCurrentDirectory(4095, originalCurrentDirectory); SetCurrentDirectory(sBinPath.c_str()); // Dynamic binding to SetDllDirectory() typedef BOOL (WINAPI *LPFNSDD)(LPCTSTR lpPathname); HINSTANCE hKernel32 = GetModuleHandle("kernel32"); LPFNSDD lpfnSetDllDirectory = (LPFNSDD)GetProcAddress(hKernel32, "SetDllDirectoryA"); if (lpfnSetDllDirectory){ lpfnSetDllDirectory(sBinPath.c_str()); } // load jvm library HINSTANCE hJVM = LoadLibrary(sJVMpath.c_str()); SetCurrentDirectory(originalCurrentDirectory); if (lpfnSetDllDirectory){ lpfnSetDllDirectory(NULL); } if( hJVM == NULL ){ vShowJREError("Java does not appear to be installed on this machine. Click OK to go to www.java.com where you can download and install Java"); return 0; } // try to start 1.2/3/4 VM // uses handle above to locate entry point CreateJavaVM lpfnCreateJavaVM = (CreateJavaVM) GetProcAddress(hJVM, "JNI_CreateJavaVM"); jintVMStartupReturnValue = (*lpfnCreateJavaVM)(&jvm, &env, &vm_args); // test for success if (jintVMStartupReturnValue < 0) { stringstream ss; ss << "There is a problem with the 32 bit Java installation on this computer ("; ss << jintVMStartupReturnValue; ss << "). Click OK to go to www.java.com where you can download and re-install 32 bit Java"; vShowJREError(ss.str()); // I don''t think we should destroy the VM - it never was created... //vDestroyVM(env, jvm); return 0; } //now check for minimum jvm version string version = ""; string errormsg = ""; if (!GetJRESystemProperty(env, "java.specification.version", version, errormsg)){ vShowJREError(errormsg); vDestroyVM(env, jvm); return 0; } double verf = atof(version.c_str()); if (verf < 1.599f){ string sErrorMessage = "This application requires Java Runtime version 1.6 or above, but your runtime is version " + version + "/n/nClick OK to go to www.java.com and update to the latest Java Runtime Environment"; vShowJREError(sErrorMessage); vDestroyVM(env, jvm); return 0; } // find startup class string sStartupClass = STARTUP_CLASS; // notice dots are translated to slashes jclassStartup = env->FindClass(sStartupClass.c_str()); if (jclassStartup == NULL) { string sErrorMessage = "Unable to find startup class [" + sStartupClass + "]"; vShowError(sErrorMessage); vDestroyVM(env, jvm); return 0; } // find startup method string sStartupMethod_Identifier = "main"; string sStartupMethod_TypeDescriptor = "([Ljava/lang/String;)V"; midStartup = env->GetStaticMethodID(jclassStartup, sStartupMethod_Identifier.c_str(), sStartupMethod_TypeDescriptor.c_str()); if (midStartup == NULL) { string sErrorMessage = "Unable to find startup method [" + sStartupClass + "." + sStartupMethod_Identifier + "] with type descriptor [" + sStartupMethod_TypeDescriptor + "]"; vShowError(sErrorMessage); vDestroyVM(env, jvm); return 0; } // create array of args to startup method jstring jstringExampleArg; jclass jclassString; jobjectArray jobjectArray_args; jstringExampleArg = env->NewStringUTF("example string"); if (jstringExampleArg == NULL){ vDestroyVM(env, jvm); return 0; } jclassString = env->FindClass("java/lang/String"); jobjectArray_args = env->NewObjectArray(__argc-argStart, jclassString, jstringExampleArg); if (jobjectArray_args == NULL){ vDestroyVM(env, jvm); return 0; } int count; for (count = argStart; count < __argc; count++){ env->SetObjectArrayElement(jobjectArray_args, count-1, env->NewStringUTF(__argv[count])); } // call the startup method - // this starts the Java program env->CallStaticVoidMethod(jclassStartup, midStartup, jobjectArray_args); string errstr; if (GetExceptionString(env, errstr)){ vShowError(errstr); } // attempt to detach main thread before exiting if (jvm->DetachCurrentThread() != 0) { vShowError("Could not detach main thread./n"); } // this call will hang as long as there are // non-daemon threads remaining jvm->DestroyJavaVM(); return 0; } void vDestroyVM(JNIEnv *env, JavaVM *jvm) { if (env->ExceptionOccurred()) { env->ExceptionDescribe(); } jvm->DestroyJavaVM(); } void vShowError(string sError) { MessageBox(NULL, sError.c_str(), "Startup Error", MB_OK); } void vShowJREError(string sError) { MessageBox(NULL, sError.c_str(), "Startup Error", MB_OK); ShellExecute(NULL, "open", "http://www.java.com", NULL, NULL, SW_SHOWNORMAL); } /* Shows an error message in an OK box with the system GetLastError appended in brackets */ void vShowLastError(string sLocalError) { LPVOID lpSystemMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpSystemMsgBuf, 0, NULL ); string sSystemError = string((LPTSTR)lpSystemMsgBuf); vShowError(sLocalError + " [" + sSystemError + "]"); } void vAddOption(string& sValue) { mctOptions++; if (mctOptions >= mctOptionCapacity) { if (mctOptionCapacity == 0) { mctOptionCapacity = 3; vm_options = (JavaVMOption*)malloc(mctOptionCapacity * sizeof(JavaVMOption)); } else { JavaVMOption *tmp; mctOptionCapacity *= 2; tmp = (JavaVMOption*)malloc(mctOptionCapacity * sizeof(JavaVMOption)); memcpy(tmp, vm_options, (mctOptions-1) * sizeof(JavaVMOption)); free(vm_options); vm_options = tmp; } } vm_options[mctOptions-1].optionString = (char*)sValue.c_str(); } /* If buffer is "c:/app/bin/java", * then put "c:/app" into buf. */ jboolean GetApplicationHome(char *buf, jint sz) { char *cp; GetModuleFileName(0, buf, sz); *strrchr(buf, ''//') = ''/0''; if ((cp = strrchr(buf, ''//')) == 0) { // This happens if the application is in a // drive root, and there is no bin directory. buf[0] = ''/0''; return JNI_FALSE; } return JNI_TRUE; } string GetClassPath(string root){ string rootWithBackslash = root; if (rootWithBackslash[rootWithBackslash.length()-1] != ''//') rootWithBackslash += "//"; string cp = rootWithBackslash + "classes//"; //first entry in the cp string libPathWithBackslash = rootWithBackslash + "lib//"; // now find all jar files... string searchSpec = libPathWithBackslash; searchSpec = libPathWithBackslash + "*.jar"; WIN32_FIND_DATA fd; HANDLE find = FindFirstFile(searchSpec.c_str(), &fd); while (find != NULL){ cp += ";"; cp += libPathWithBackslash; cp += fd.cFileName; if (!FindNextFile(find, &fd)){ FindClose(find); find = NULL; } } return cp; } string GetJREPath(){ // first, check for JRE in application directory char home[2000]; if (!GetApplicationHome(home, sizeof(home))) { vShowError("Unable to determine application home."); return 0; } string sJREPath(home); sJREPath += "//jre"; if (PathExists(sJREPath)){ return sJREPath; } /* - don''t check JAVA_HOME - it may be incorrect... // next, check the JAVA_HOME environment variable GetEnvironmentVariable("JAVA_HOME", home, sizeof(home)); sJREPath = home; if (PathExists(sJREPath)){ return sJREPath; } */ // next, check registry HKEY hKeyJRERoot; HKEY hKeyJREInstance; DWORD dwType; DWORD dwSize; BYTE *pData; string valueName; string value; LONG regRslt; sJREPath = ""; regRslt = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE//JavaSoft//Java Runtime Environment", 0, KEY_READ, &hKeyJRERoot); if (regRslt == ERROR_SUCCESS){ valueName = "CurrentVersion"; regRslt = RegQueryValueEx(hKeyJRERoot, valueName.c_str(), NULL, &dwType, NULL, &dwSize); if (regRslt == ERROR_SUCCESS){ pData = (BYTE *)malloc(dwSize); value = ""; regRslt = RegQueryValueEx(hKeyJRERoot, valueName.c_str(), NULL, &dwType, pData, &dwSize); if (regRslt == ERROR_SUCCESS){ value = (LPCSTR)pData; } free(pData); if (value != ""){ regRslt = RegOpenKeyEx(hKeyJRERoot, value.c_str(), 0, KEY_READ, &hKeyJREInstance); if (regRslt == ERROR_SUCCESS){ valueName = "JavaHome"; value = ""; regRslt = RegQueryValueEx(hKeyJREInstance, valueName.c_str(), NULL, &dwType, NULL, &dwSize); if (regRslt == ERROR_SUCCESS){ pData = (BYTE *)malloc(dwSize); regRslt = RegQueryValueEx(hKeyJREInstance, valueName.c_str(), NULL, &dwType, pData, &dwSize); if (regRslt == ERROR_SUCCESS){ value = (LPCSTR)pData; sJREPath = value; } free(pData); } RegCloseKey(hKeyJREInstance); } } } RegCloseKey(hKeyJRERoot); } return sJREPath; } 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; }


Una opción más ... trabajo en un lanzador llamado WinRun4J , que le permite especificar un tamaño máximo de almacenamiento dinámico como porcentaje de la memoria disponible en la máquina en la que se está ejecutando (es decir, verifica la cantidad de memoria disponible y establece el parámetro -Xmx dinámicamente en el inicio).

La opción INI es "vm.heapsize.max.percent". También hay otra opción "vm.heapsize.preferred", que establece el parámetro -Xmx como el máximo de memoria disponible en la máquina hasta esta cantidad.

Creo que algunos de los otros lanzadores (por ejemplo, Launch4J, Janel) ofrecen la misma funcionalidad.


¿Ha observado ejecutar jps para darle el PID para su proceso y luego llamar a jinfo para cambiar la opción mx? No estoy seguro de si esto funcionará pero puede.

[Editar] Esto significaría que cuando crees que tienes un gran conjunto de datos, lees la cantidad total de RAM de algún modo (creo que depende del sistema operativo. Ver http://forums.sun.com/thread.jspa?messageID=10306570 ) o simplemente aumenta el tamaño hasta que ya no creas que es bajo (si explota primero, intenta capturar y mostrar un mensaje útil como "tu máquina es inadecuada, es hora de correr hacia Frys").


Esta discusión es discutible si cree que sus clientes pueden solicitar 2-3 GB de RAM en su máquina de 32 bits. El sistema operativo y otras aplicaciones tomarán su libra de carne para funcionar también.

Parece que su aplicación está llegando al punto en que necesita un sistema operativo de 64 bits y mucha más memoria RAM.