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

时间:2009-07-20 09:09:56

标签: java command-line virtual-memory

我们发布了一个Java应用程序,其内存需求可能会有很大差异,具体取决于它正在处理的数据大小。如果您没有经常设置最大VM(虚拟内存)大小 JVM退出大数据时出现GC故障。

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

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

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

14 个答案:

答案 0 :(得分:13)

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

根据[文件] [1]:

  

-XX:+ AggressiveHeap选项   检查机器资源(大小   内存和处理器数量)   并尝试设置各种参数   最适合长时间运行的记忆   分配密集型工作。它是   最初用于机器   大量的内存和大量的内存   CPU数量,但在J2SE中   平台,版本1.4.1及更高版本   已证明自己甚至有用   四台处理器机器。有了这个   选项吞吐量收集器   (-XX:+ UseParallelGC)一起使用   具有自适应尺寸   (-XX:+ UseAdaptiveSizePolicy)。该   机器上的物理内存必须   之前至少要256MB   可以使用AggressiveHeap。尺寸   初始堆的计算   根据物理的大小   记忆和尝试使最大化   使用物理内存   堆(即,算法尝试   使用几乎与总数一样大的堆   物理记忆)。

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

答案 1 :(得分:8)

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

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

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

答案 2 :(得分:8)

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

  1. 拥有一个有意义的进程名称(尤其是在windows下)
  2. 拥有我们自己的图标(同样,对Windows很重要)
  3. 动态构建类路径(我们解析/ lib文件的内容以自动包含所有jar)
  4. 对于我们的应用程序,我们只是硬编码堆限制,但您可以根据可用内存轻松动态配置最大堆大小。

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

    这里的代码不仅可以启动JVM等,还可以根据计算机的可用RAM确定最大堆空间。对于SO帖子来说,这是很多代码,而且它根本不是很好 - 但这是经过强制验证的代码 - 它已经被使用了近十年,已经安装了数百个等等...享受:

    #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;
    }
    

答案 3 :(得分:7)

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

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

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

答案 4 :(得分:5)

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

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

我担心会有点痛苦。

答案 5 :(得分:4)

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

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

答案 6 :(得分:1)

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

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

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

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

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

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

# 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

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

答案 9 :(得分:0)

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

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

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

答案 10 :(得分:0)

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

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

答案 11 :(得分:0)

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

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

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

答案 12 :(得分:0)

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

[编辑]这意味着当你认为你拥有一个大数据集时,你会以某种方式读取ram的总量(我认为是操作系统依赖。请参阅http://forums.sun.com/thread.jspa?messageID=10306570)或者只是增加大小直到你不知道我认为它已经很低了(如果它先爆炸,试着捕捉并显示一条有用的信息,例如“你的机器不足,是时候跑到弗里斯”了。)

答案 13 :(得分:-1)

如果您认为您的客户可以在其32位计算机上请求2-3GB的RAM,则此讨论没有实际意义。操作系统和其他应用程序也将运行他们的一磅肉。

听起来您的应用程序已达到需要64位操作系统和更多RAM的程度。