سؤال

أنا أحصل على OutofMemoryError: كومة جافا

قصاصات الطريقة:

{
// step 1: I am creating a 2 dim array
  int totalCombination = (int) Math.pow(2.0, (double) vowelCount);
// here vowelCount > 10

// step2: initializing my array
// step3: and using that array
}

سؤالي:

في كل مرة يطلق عليها هذه الطريقة ، يتم إنشاء هذه الصفيف. هل من الممكن أن يتم إطلاق الصفيف.

في Windows TaskManager ، يمكنني رؤية الذاكرة المستخدمة من قبل Java هي تدريجية بحتة. لذلك ليس ذلك في حجم الكومة أقل ، ولكن يتم استخدام الذاكرة بشكل متكرر ولا يتم إطلاقها بطريقة أو بأخرى.

واسمحوا لي أن أعرف إذا كنت بحاجة إلى مزيد من detal.

الرجاء المساعدة في تصحيح الخطأ.

أنوج

جزء الكود الذي قد يسبب الخطأ:

int totalcombination = (int) Math.Pow (2.0 ، (double) حرف علة) ؛

    int lookupArray[][] = new int[totalCombination][vowelCount];

    // initialize lookupArray

    for (int i = 0; i < totalCombination; i++) {
        for (int j = 0; j < vowelCount; j++) {
            lookupArray[i][j] = 0;
        }
    }

    // populate lookupArray
    //vowelCount : number of vowels in a word
    // if count is 2, then array will contain 00,01,10,11

    for (int i = 1; i < totalCombination; i++) {
        for (int c = 0; c < vowelCount; c++) {
            lookupArray[i][c] = lookupArray[i - 1][c];
        }
        boolean flag = true;
        for (int j = vowelCount - 1; j >= 0 && flag; j--) {
            if (lookupArray[i - 1][j] == 1) {
                lookupArray[i][j] = 0;
            } else if (lookupArray[i - 1][j] == 0) {
                lookupArray[i][j] = 1;
                flag = false;
            }
        }
    }


  // this part total combination of a word having different combination of vowels in it.


    for (int i = 0; i < totalCombination; i++) {
        int vcount = vowelCount - 1;
        StringBuffer stringBuffer = new StringBuffer();

        for (int j = 0; j < word.length(); j++) {
            if (wordArr[j] == 'a' || wordArr[j] == 'e' || wordArr[j] == 'i'
                    || wordArr[j] == 'o' || wordArr[j] == 'u') {
                if (lookupArray[i][vcount] == 1) {
                    stringBuffer.append(wordArr[j]);
                }
                vcount--;
            } else {
                stringBuffer.append(wordArr[j]);
            }
        }
هل كانت مفيدة؟

المحلول

صلاحيات اثنين تنمو أضعافا مضاعفة. إذا vowelCount عالية ، مجموعة واحدة وحدها يمكن أن تسبب بسهولة OutOfMemoryError (2^32 = 4GB).

يمكنك محاولة تعديل متطلبات الذاكرة القصوى VM (على سبيل المثال -Xmx512m) ، لكن تدرك أن الخوارزمية تتطلب الكثير من الذاكرة. قد ترغب في العثور على خوارزمية أفضل إذا كان ذلك ممكنًا.


أنظر أيضا


بعد التحرير: كما كنت أتوقع ، فإنك تولد مجموعة ضخمة مليئة بجميع الاحتمالات الثنائية. نادراً ما تحتاج إلى تخزين هذه المجموعة بأكملها في الذاكرة. يمكنك فقط توليد كل مجموعة ممكنة "على الطيران" وإطعامها لمن يحتاج إلى 0S و 1S "في الوقت المناسب".

ضع في اعتبارك أن هذا لا يزال نموًا أسيًا ، لذلك على الرغم من أنك تعتني بمتطلبات الذاكرة الخاصة بك من O(2^N) لمجرد O(N), لا يزال تعقيد الوقت الخاص بك O(2^N).

في كل مرة يطلق عليها هذه الطريقة ، يتم إنشاء هذه الصفيف. هل من الممكن أن يتم إطلاق الصفيف.

نعم ، هذا ممكن للغاية ، إذا تم تسريب الإشارة إلى الصفيف على الإطلاق ، ثم يتمسك بشيء ما في هذا المرجع. جامع القمامة لا يهتم حقًا بماذا أنت أعتقد أنه/ليس القمامة. طالما أن الكائن يشار إليه بشيء (وهو ليس مرجعًا ضعيفًا وما إلى ذلك) ، فهو ليس قمامة.


بعد اكتشاف ما تحاول القيام به ، هذا هو الحل. لاحظ أنه لا يولد مجموعة من البتات على الإطلاق.

static void generate(String prefix, String suffix) {
    int i = suffix.replaceAll("[aeiou].*", "").length();
    if (i == suffix.length()) {
        System.out.println(prefix + suffix);
    } else {
        generate(prefix + suffix.substring(0, i), suffix.substring(i + 1));
        generate(prefix + suffix.substring(0, i+1), suffix.substring(i + 1));
    }
}

// generate("", "apple");

يستخدم Regex للعثور على مكان حرف العلة التالي. يمكنك استخدام حلقة منتظمة بدلاً من ذلك وستظل الخوارزمية العامة تعمل. يمكنك تحسينه للاستخدام StringBuilder بدلاً من ذلك (سأذهب في الغالب إلى وصول وضوح الوضوح في هذا المقتطف).


إليك حل بديل يستخدم split لتسمية سلسلة الإدخال إلى قطع (O(N) الفضاء) ، ثم يستخدم StringBuilder لتوليد جميع الأوتار الأخرى (O(N) الفضاء).

static void generate(StringBuilder sb, String[] parts, int i) {
    if (i == parts.length) {
        System.out.println(sb.toString());
    } else {
        if ("aeiou".contains(parts[i])) {
            generate(sb, parts, i + 1);
        }
        sb.append(parts[i]);
        generate(sb, parts, i + 1);
        sb.setLength(sb.length() - parts[i].length());
    }
}
static void generate(String s) {
    generate(
        new StringBuilder(),
        s.split("(?<=[aeiou])|(?=(?!^)[aeiou])"),
        0
    );
}

// generate("apple");

انقسامات regex "apple" داخل [ "a", "ppl", "e" ]. ينقسم في كل مكان بعد حرف العلة ، أو (إذا لم تكن بداية السلسلة) في كل مكان قبل حرف العلة.

يجب أن يكون من الواضح الآن أن متطلبات المساحة O(N), ، لذلك ما لم تكن سلسلة الخاص بك يبعث على السخرية, ، هذا لا ينبغي أن يسبب OutOfMemoryError.

بالطبع ، إذا كنت تخزين السلاسل المولدة - كل شيء O(2^N) منهم - في الذاكرة بعد ذلك بالطبع ستحصل OutOfMemoryError. آمل أن تكون هذه الحقيقة واضحة.

الفكرة بأكملها هو عدم تخزين أي شيء لا تحتاجه لإنشاء هذا الإخراج الضخم. إذا قمت بتخزين كل هذا الإخراج الضخم في الذاكرة (بدلاً من ، على سبيل المثال ، طباعتها stdout أو ملف) ثم يهزم الغرض كله وستحصل على OutOfMemoryError كما هو متوقع.

نصائح أخرى

قد ترغب في التفكير في استخدام profiler التي يمكن أن تعطيك صورة عن أنواع الكائنات الموجودة في أي وقت معين في البرنامج. على سبيل المثال ، لدى NetBeans مستنيرًا مدمجًا.

مع ما يقال ، فإن الجاني المحتمل هو-كما أشار من قبل الآخرين-كمية عالية من الذاكرة للغاية التي سيتطلبها صفيفك ثنائي الأبعاد مع نمو عدد الحروف المتحركة.

أفترض أن لديك شيء مثل الرمز التالي:

int totalCombination = 1 << vowelCount;
System.out.println("totalCombination = " + totalCombination);
System.out.println("totalCombination (in Millions) = " + totalCombination / 1000 / 1000);

int[] arr = new int[totalCombination];

في 32 بت VM ، لا يمكن أن ينمو المصفوفة أكثر من 4 جيجابايت ، أي 1024 مليون مشاركة. تأكد من أنك دائمًا ما تحصل على أرقام أصغر مطبوعة في الكود أعلاه.

وربما يجب أن تأخذ خوارزمية مختلفة تماما. ولكن لذلك يجب أن تخبرنا بما تريد تحقيقه ، لا كيف أنت تحاول ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top