16

処理するデータのサイズによってメモリ需要が大きく異なる Java アプリケーションを出荷しています。VM (仮想メモリ) の最大サイズを設定しないと、多くの場合、JVM はビッグ データの GC 障害で終了します。

私たちが見たいのは、使用可能な VM の合計が使い果たされるまで、GC が十分なメモリを提供できないため、JVM がより多くのメモリを要求することです。たとえば、128Mb から始めて、GC が失敗するたびに幾何学的に (または他のステップで) 増やします。

JVM (「Java」) コマンド ラインでは、最大 VM サイズ (さまざまな -Xm* コマンド) を明示的に設定できます。これは、アプリケーションに同梱されている .cmd ファイルで実行しようとしています。しかし、特定の数値を選択すると、次の 2 つの悪い動作のいずれかが発生します。1) 数値がほとんどのターゲット システム (1Gb など) で動作するのに十分小さい場合、ビッグ データには十分な大きさではありません。非常に大きくすると、JVM は実際の VM が指定よりも小さいシステムでの実行を拒否します。

必要に応じて使用可能な VM を使用するように Java を設定するには、事前にその数を知らず、起動時にすべてを取得する必要はありません。

4

14 に答える 14

13

オプションを使用することもできます: -XX:+AggressiveHeap

[ドキュメント][1]によると、これ:

-XX:+AggressiveHeap オプションは、マシンのリソース (メモリのサイズとプロセッサの数) を検査し、実行時間の長いメモリ割り当て集中型のジョブに最適なさまざまなパラメータを設定しようとします。当初は大量のメモリと多数の CPU を搭載したマシンを対象としていましたが、J2SE プラットフォーム バージョン 1.4.1 以降では、4 プロセッサ マシンでも有用であることが示されています。このオプションでは、スループット コレクター (-XX:+UseParallelGC) がアダプティブ サイジング (-XX:+UseAdaptiveSizePolicy) と共に使用されます。AggressiveHeap を使用するには、マシンの物理メモリが少なくとも 256MB 必要です。初期ヒープのサイズは、物理メモリのサイズに基づいて計算され、ヒープの物理メモリを最大限に使用しようとします (つまり、

[1]: http://java.sun.com/docs/hotspot/gc1.4.2/#4.2.2 . AggressiveHeap|アウトライン

于 2009-07-20T10:26:25.460 に答える
8

JNIを介してすべてのJavaアプリケーションを起動するために使用する小さなCアプリケーションがあります。これにより、次のことが可能になります。

  1. 意味のあるプロセス名を付ける(特にWindowsでは重要)
  2. 独自のアイコンを用意する(これもWindowsにとって重要です)
  3. クラスパスを動的に構築します(/ libファイルの内容を解析して、すべてのjarを自動インクルードします)

私たちのアプリでは、ヒープ制限をハードコーディングするだけですが、使用可能なメモリに基づいて最大ヒープサイズを簡単に動的に構成できます。

この種の小さなアプリは、実際には非常に簡単に実行できます(JNIで実行するのが最も簡単なことの1つです)。良い出発点は、JDKのソースです(使用できるjava.exe自体のサブフォルダーがあります-それが私たちが行ったことです)。ほとんどの人は、java.exeがJNIを呼び出してコマンドライン引数を渡すだけの小さなアプリケーション(200行未満のコード)であることを知って非常に驚いています(ええと、main()と呼ばれるメソッドの使用でさえ一度はかなりオプションです自分で起動を開始します)。

これは、JVMなどを起動するだけでなく、コンピューターの使用可能なRAMに基づいて最大ヒープスペースを決定するコードです。これはSO投稿用の多くのコードであり、まったくきれいではありません-しかし、これは戦いで強化されたコードです-何百ものインストールなどでほぼ10年間使用されています...お楽しみください:

#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;
}
于 2009-07-21T04:40:14.613 に答える
8

VM の最大サイズは確かにそのニーズに応えます (最大値を設定しますが、VM は必要なだけステップバイステップで実行します)。方法(ただし、もう少し検索します)

[編集] 最初のプログラム/スクリプト (または別の Java プログラム) を使用して、システムで利用可能なリソースをチェックし、 system から取得したものに従って、適切な -Xm でのみプログラムを呼び出すのはどうですか? そうすれば、それまで機械を知らなくても、機械に適応することができます。アイデアかもしれません...

[2 回目の編集] わかりました、これはすでにskaffmanによって提案されています。

于 2009-07-20T09:14:17.993 に答える
7

もう1つのオプション... WinRun4Jというランチャーを使用しています。これにより、実行中のマシンで使用可能なメモリの割合として最大ヒープサイズを指定できます(つまり、使用可能なメモリの量をチェックし、 -Xmx パラメータを起動時に動的に設定します)。

INI オプションは「vm.heapsize.max.percent」です。別のオプション「vm.heapsize.preferred」もあります。これは、-Xmx パラメーターを、マシンで使用可能な最大メモリ量として設定します。

他のいくつかのランチャー (Launch4J、Janel など) も同じ機能を提供していると思います。

于 2009-07-21T12:29:57.700 に答える
5

あなたは運が悪いと思います :-(-Xms-Xmxオプションはその柔軟性を提供しません。

したがって、メモリの最大量を決定できるスクリプトで JVM 呼び出しをラップし、適切に設定する必要があると思います(おそらく、 Windows でWMI-Xmxを使用する .vbs スクリプト)。それとも、初めて実行するときにユーザーに尋ねるのでしょうか?

ちょっと痛いですよね。

于 2009-07-20T09:15:56.710 に答える
4

これを行う最も簡単な方法は、ラッパー アプリケーションを介して JVM を起動し、システム リソースをチェックしてメモリの可用性を判断し、適切な -Xmx パラメータを使用して JVM を起動することだと思います。

問題は、そのラッパーをどのように作成するかです。API やシステム プロパティが必要な情報を公開するとは思えませんが、ラッパー アプリ自体が JVM になる可能性さえあります。おそらく、シェルスクリプトまたはあなたの選択が情報を取得する可能性があります。

于 2009-07-20T09:19:29.400 に答える
1

時間がたくさんある場合は、次のことを試すことができます。

必要なメモリと入力データセットを取得してみてください。これにより、処理を異なるクラスのセットに分割し、実際にデータを処理する新しい JVM プロセスを作成できます。基本的にマネージャーとワーカー。Manager は要求されたデータセットに対して基本的な分析を行い、適切なメモリ要件を持つ Worker を生成します。おそらく、マネージャーが環境を認識するように設定し、マシンが処理できないデータセットを操作しようとしたときにユーザーに警告することもできます。

これは skaffman によって提供された回答のほとんどの拡張ですが、ユーザーに関する限り、同じアプリ内ですべて発生します。

于 2009-07-20T10:13:28.060 に答える
0

SunとIBMJVMのどちらもこれを実行できるとは思いません(AS / 400が実行できることは知っていますが、それはおそらくあなたには関係ありません)。

「小さなインスタンス」を提供できるので、Java WebStartを使用することをお勧めします(これを破棄する前に、Java 6 u 10で更新されており、「ローカル」アプリケーションとアプレットの起動にはるかに適していることに注意してください)。 、「より大きなインスタンス」、「巨大なインスタンス」をリンク/アイコンとして。

ほとんどの場合、「Webstartキャッシュにアプリケーションを挿入する」オプションと「オフライン」オプションを調べます。

于 2009-07-20T10:04:27.423 に答える
0

コメントでは、アプリケーションが実際に使用するメモリの量は、ユーザーが提供する入力データセットのサイズに依存すると述べています。これは、使用可能なすべての仮想メモリを取得しようとするのではなく(ユーザーの他のアプリケーションに問題を引き起こす可能性があります)、JVMを起動する前に入力データセットのサイズを確認し、それを使用してアプリケーションに必要なメモリの量を見積もる必要があることを示しています。 。

ユーザーのマシンが適度な物理メモリと巨大なスワップスペースで構成されていると仮定します。巨大なVMサイズでJVMを起動すると、JVMが非常駐ページのデータにアクセスしようとするため、深刻な「スラッシング」が発生する可能性があります。対照的に、JVMにアプリケーションが必要とするものよりも多く、使用可能な物理メモリよりも少ないものを与えると、スラッシングすることなく快適に実行できるはずです。

于 2009-07-21T06:12:51.587 に答える
0

あなたがやろうとしていることはできないと思います。代わりに、顧客、そのシステム、およびより多くのメモリを許可するためにファイルを変更する方法についての顧客の要求に固有の指示を送信する必要があります。.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

または、ユーザーが最初に製品を注文するときに指定する製品オプションに応じて、異なる構成ファイルを展開する可能性があります。

于 2009-07-20T09:18:06.033 に答える
0

仮想マシンの引数には、使用できる 2 つのオプションがあります。起動時のメモリ サイズを設定する -Xms と、最大メモリ サイズを設定する -Xmx...

低い起動メモリと大きな最大メモリを設定できるため、VM は必要な場合にのみ新しいメモリを割り当てます。

于 2009-07-20T09:14:16.620 に答える
-1

クライアントが32ビットマシンで2〜3 GBのRAMを要求できると考える場合、この議論は議論の余地があります。OSやその他のアプリも同様に実行するために彼らの肉のポンドを取ります。

アプリが64ビットオペレーティングシステムとより多くのRAMを必要とする段階に達しているようです。

于 2009-07-20T09:42:50.587 に答える