获取JVM以根据需要增加内存需求,直至达到VM限制的大小?

我们发布了一个Java应用程序,其内存需求可能会有很大差异,具体取决于它正在处理的数据大小。 如果未设置最大VM(虚拟内存)大小,则JVM通常会在大数据上因GC失败而退出。

我们希望看到的是,JVM请求更多内存,因为GC无法提供足够的内存,直到总可用VM耗尽为止。 例如,以128Mb开始,并在GC失败时增加几何(或其他一些步骤)。

JVM(“Java”)命令行允许显式设置最大VM大小(各种-Xm *命令),并且您认为这将被设计为足够的。 我们尝试在随应用程序提供的.cmd文件中执行此操作。 但是如果你选择任何特定的数字,你会得到两种不良行为之一:1)如果你的数字足够小,可以在大多数目标系统上工作(例如,1Gb),那么它对于大数据来说不够大,或者2)如果如果它非常大,JVM拒绝在实际VM小于指定的系统上运行。

如何设置Java以在需要时使用可用的VM,而不事先知道这个数字,并且在启动时没有抓住它?

您还可以使用选项:-XX:+ AggressiveHeap

这根据[文档] [1]:

-XX:+ AggressiveHeap选项检查机器资源(内存大小和处理器数量),并尝试将各种参数设置为长时间运行的内存分配密集型作业的最佳选择。 它最初用于具有大量内存和大量CPU的计算机,但在J2SE平台1.4.1及更高版本中,它已经certificate即使在四处理器计算机上也很有用。 使用此选项,吞吐量收集器(-XX:+ UseParallelGC)与自适应大小调整一起使用(-XX:+ UseAdaptiveSizePolicy)。 在使用AggressiveHeap之前,计算机上的物理内存必须至少为256MB。 初始堆的大小是根据物理内存的大小计算的,并尝试最大限度地利用堆的物理内存(即,算法尝试使用几乎与总物理内存一样大的堆)。

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

最大VM大小确实满足了这个需求(它设置了最大值,但VM只需要一步一步),但是如果你需要多个配置,除了提供不同的“cmd”文件外,我还没看到一种方式(虽然我会搜索更多)

[编辑]如何使用第一个程序/脚本(甚至是另一个java程序)来检查系统的可用资源,然后根据从系统中检索到的内容,只使用相应的-Xm调用程序? 这样它就能适应机器,即使你以前不知道它们。 可能是个主意……

[第二次编辑]好的,这已经被skaffman提出了,我的不好。

我们有一个小型C应用程序,用于通过JNI启动所有Java应用程序。 这允许我们:

  1. 有一个有意义的进程名称(尤其是在windows下)
  2. 有我们自己的图标(再次,对Windows很重要)
  3. 动态构建类路径(我们解析/ lib文件的内容以自动包含所有jar)

对于我们的应用程序,我们只是硬编码堆限制,但您可以根据可用内存轻松动态配置最大堆大小。

这种小应用程序实际上很容易做到(这是与JNI最简单的事情之一)。 一个很好的起点将是JDK的源代码(你可以使用java.exe本身的子文件夹 – 这就是我们所做的)。 大多数人都非常惊讶地发现java.exe是一个很小的应用程序(<200行代码)只调用JNI并传递命令行参数(哎呀,即使使用名为main()的方法也是非常可选的一次你自己开始推出的东西)。

这里的代码不仅可以启动JVM等,还可以根据计算机的可用RAM确定最大堆空间。 这是SOpost的很多代码,它一点也不漂亮 – 但这是经过强制攻击的代码 – 它已经被使用了近十年,已经安装了数百个等等…享受:

 #include  #include  #include  #include  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), eg 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; } 

还有一个选项……我在一个名为WinRun4J的启动器上工作,它允许你指定最大堆大小作为其运行的机器上可用内存的百分比(即,它检查可用的内存量和在启动时动态设置-Xmx参数。

INI选项是“vm.heapsize.max.percent”。 还有另一个选项“vm.heapsize.preferred”,它将-Xmx参数设置为计算机上的最大可用内存,直到此数量。

我相信其他一些发射器(例如Launch4J,Janel)提供相同的function。

我认为你运气不好:-( -Xms-Xmx选项不提供这种灵活性。

所以我认为您需要使用可以确定最大内存量的脚本来包装JVM调用,然后适当地设置-Xmx (可能是在Windows上使用WMI的.vbs脚本)。 或者它可能会在用户第一次运行时询问用户?

我担心会有点痛苦。

我认为最简单的方法是通过一些包装器应用程序启动JVM,该应用程序将检查系统资源以确定内存可用性,然后使用适当的-Xmx参数启动JVM。

那么问题就变成了如何编写包装器。 甚至包装器应用程序本身可能是JVM,尽管我认为API或系统属性不会公开必要的信息。 也许shell脚本或您的选择可以获取信息。

如果你有很多时间在手上,你可以尝试以下方法:

尝试获取所需的内存与输入数据集。 通过这种方式,您可以在不同的类集中拆分处理,并创建一个新的JVM进程来实际处理数据。 基本上是经理和工人。 管理器将对所需数据集进行基本分析,并生成具有适当内存要求的Worker。 您可能还可以将Manager设置为了解环境,并在用户尝试操作其计算机无法处理的数据集时发出警告。

这几乎是skaffman提供的答案的延伸,但就用户而言,它将在同一个应用程序中发生。

可以使用虚拟机参数中的两个选项:-Xms用于设置启动时的内存大小,-Xmx用于设置最大内存大小…

您可以设置较低的启动内存和最大的启动内存,因此VM仅在需要时才会分配新的内存。

我不认为Sun或IBM JVM可以做到这一点(我知道AS / 400可以,但这很可能与您无关)。

我建议使用Java WebStart(在丢弃之前,请注意它已经使用Java 6 u 10更新,并且更适合启动“本地”应用程序和applet),因为它允许您提供“小实例” ,“更大的实例”,“巨大的实例”作为链接/图标。

您很可能会查看“在webstart缓存中注入应用程序”和“离线”选项。

我认为你不能做你想做的事; 相反,您必须发送特定于客户的指令 ,他们的系统以及他们如何修改.cmd文件以允许更多内存的要求。

当然,如果您的产品针对的是非技术性用户,您可能希望将其隐藏在更加用户友好的配置文件背后。 例如

 # 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 

或者可能部署不同的配置文件,具体取决于用户在首先订购产品时指定的产品选项

在评论中,您说应用程序实际依赖于用户提供的输入数据集大小的内存量。 这表明,您应该在启动JVM之前查看输入数据集大小,并使用它来估计应用程序需要的内存量,而不是尝试获取所有可用的虚拟内存(这可能会导致用户的其他应用程序出现问题)。 。

假设用户的计算机配置了适度的物理内存和巨大的交换空间。 如果启动具有巨大VM大小的JVM,则当JVM尝试访问非驻留页面中的数据时,可能会导致严重的“颠簸”。 相比之下,如果你给JVM提供的东西比应用程序需要的多,而且比可用的物理内存少,那么你应该能够舒适地运行而不会发生颠簸。

我通读了线程,但没有看到任何表明该应用程序已进行某种分析的内容。 通常情况下,我会在特定条件下对应用进行分析,以查找性能或内存使用情况的热点。 在大多数情况下,可能会有所改进。

如果您可以确定限制并了解应用程序的行为,您可以更好地告诉客户他们对应用程序可以做什么或不做什么,从而减少支持呼叫的数量,让您更好地了解最低要求或用于运送产品的最大堆大小。

也许你可以从这开始: http : //www.eclipse.org/mat/

您是否看过运行jps为您的进程提供PID,然后调用jinfo来更改mx选项? 不确定这是否有效但可能。

[Edit] This would mean that when you think you have a big dataset, you read the total amount of ram somehow (OS dependent I think. See http://forums.sun.com/thread.jspa?messageID=10306570 ) or you just increase the size until you don’t think it is low anymore (if it blows up first, try to capture and display a helpful message such as “your machine is inadequate, time to make a run to Frys”).

This discussion is moot if you think that your clients can ask for 2-3GB of RAM on their 32-bit machine. The OS and other apps will be taking their pound of flesh to run as well.

Sounds like your app is reaching the point where it needs a 64-bit operating system and lots more RAM.