একটি আউটআফমিউরিয়র ফেলে দেওয়ার জন্য অপর্যাপ্ত মেমরি থাকলে কী হবে?


207

আমি সচেতন যে প্রতিটি বস্তুর জন্য হ্যাপ মেমরি প্রয়োজন এবং স্ট্যাকের প্রতিটি আদিম / রেফারেন্সের জন্য স্ট্যাক মেমরির প্রয়োজন।

আমি যখন স্তূপে একটি অবজেক্ট তৈরি করার চেষ্টা করি এবং এটি করার জন্য পর্যাপ্ত স্মৃতি নেই, তখন জেভিএম একটি জাভা.এল.আং.আউটআউফ মেমরিরির তৈরি করে এবং আমার কাছে ফেলে দেয়।

সুতরাং অন্তর্নিহিত, এর অর্থ এই যে JVM দ্বারা শুরুতে কিছু স্মৃতি সংরক্ষিত আছে।

এই সংরক্ষিত মেমরিটি ব্যবহার করা হলে (এটি অবশ্যই ব্যবহার করা হবে, নীচে আলোচনাটি পড়ুন) এবং জাভা.এল.আউটআফ মেমরিরির একটি উদাহরণ তৈরি করার জন্য জেভিএমের স্তূপে পর্যাপ্ত মেমরি নেই ?

এটা কি শুধু ঝুলছে? বা ওএম nullএর কোনও newউদাহরণের কোনও স্মৃতি নেই বলে সে আমাকে ফেলে দেবে ?

try {
    Object o = new Object();
    // and operations which require memory (well.. that's like everything)
} catch (java.lang.OutOfMemoryError e) {
    // JVM had insufficient memory to create an instance of java.lang.OutOfMemoryError to throw to us
    // what next? hangs here, stuck forever?
    // or would the machine decide to throw us a "null" ? (since it doesn't have memory to throw us anything more useful than a null)
    e.printStackTrace(); // e.printStackTrace() requires memory too.. =X
}

==

কেন জেভিএম পর্যাপ্ত মেমরি সংরক্ষণ করতে পারে না?

মেমরিটি কতটুকু সংরক্ষিত থাকুক না কেন, যদি এখনও জেভিএমের সেই স্মৃতিটিকে "পুনরায় দাবি করা" না থাকে তবে সেই স্মৃতিটি ব্যবহার করা এখনও সম্ভব:

try {
    Object o = new Object();
} catch (java.lang.OutOfMemoryError e) {
    // JVM had 100 units of "spare memory". 1 is used to create this OOM.
    try {
        e.printStackTrace();
    } catch (java.lang.OutOfMemoryError e2) {
        // JVM had 99 units of "spare memory". 1 is used to create this OOM.
        try {
            e.printStackTrace();
        } catch (java.lang.OutOfMemoryError e3) {
            // JVM had 98 units of "spare memory". 1 is used to create this OOM.
            try {
                e.printStackTrace();
            } catch (java.lang.OutOfMemoryError e4) {
                // JVM had 97 units of "spare memory". 1 is used to create this OOM.
                try {
                    e.printStackTrace();
                } catch (java.lang.OutOfMemoryError e5) {
                    // JVM had 96 units of "spare memory". 1 is used to create this OOM.
                    try {
                        e.printStackTrace();
                    } catch (java.lang.OutOfMemoryError e6) {
                        // JVM had 95 units of "spare memory". 1 is used to create this OOM.
                        e.printStackTrace();
                        //........the JVM can't have infinite reserved memory, he's going to run out in the end
                    }
                }
            }
        }
    }
}

বা আরও সংক্ষিপ্তভাবে:

private void OnOOM(java.lang.OutOfMemoryError e) {
    try {
        e.printStackTrace();
    } catch (java.lang.OutOfMemoryError e2) {
        OnOOM(e2);
    }
}

2
আপনার উত্তরটি অনেকাংশে জেভিএম নির্ভর করবে
মোজেনরথ

23
একটি টেলিফোন লাইব্রেরি আমি একবার ব্যবহার করেছি (90 এর দশকে) ধরে OutOfMemoryException
ফেলতাম

@ টমহাউটিন-ট্যাকলাইন যদি সেই কাজগুলিতে জড়িত অপারেশনগুলিতে অন্য একটি ওওকে ফেলে দেয় তবে কী হবে?
পেসারিয়ার

38
সেলফোনের মতো এটিও ব্যাটারি শেষ হয়ে যায় তবে স্প্যামিং রাখতে "আপনার ব্যাটারি শেষ হয়ে গেছে" রাখতে পর্যাপ্ত ব্যাটারি রয়েছে।
কাজুমা

1
"এই সংরক্ষিত মেমরিটি ব্যবহার করা হলে কী হয়": প্রোগ্রামটি যদি প্রথমটি ধরা পড়ে OutOfMemoryErrorএবং এর কোনও রেফারেন্স ধরে রাখে তবেই এটি ঘটতে পারে । এটি স্থানান্তরিত করে যে একটি ধরা পড়ার OutOfMemoryErrorমতো ততটা কার্যকর নয়, কারণ আপনার প্রোগ্রামটি ধরার বিষয়ে আপনি তার অবস্থান সম্পর্কে প্রায় কিছুই গ্যারান্টি দিতে পারবেন । দেখুন stackoverflow.com/questions/8728866/...
Raedwald

উত্তর:


145

জেভিএম আসলেই স্মৃতি থেকে যায় না। এটি ইতিমধ্যে গাদা স্ট্যাকের মেমরি গণনা করে।

জেভিএম গঠন, অধ্যায় 3 , বিভাগ 3.5.2 পদ বলে:

  • জাভা ভার্চুয়াল মেশিন স্ট্যাকগুলি যদি গতিশীলভাবে প্রসারিত করা যায়, এবং প্রসারণের চেষ্টা করা হয় তবে সম্প্রসারণের প্রভাবের জন্য অপর্যাপ্ত মেমরি উপলব্ধ করা যায়, বা যদি নতুন থ্রেডের জন্য প্রাথমিক জাভা ভার্চুয়াল মেশিন স্ট্যাক তৈরি করার জন্য অপর্যাপ্ত মেমরি উপলব্ধ করা যায়, জাভা ভার্চুয়াল মেশিন নিক্ষেপ একটি OutOfMemoryError

জন্য গাদা , বিভাগ 3.5.3।

  • যদি কোনও গণনার স্বয়ংক্রিয় স্টোরেজ ম্যানেজমেন্ট সিস্টেম দ্বারা উপলব্ধ করা যায় তার চেয়ে বেশি গাদা প্রয়োজন হয়, জাভা ভার্চুয়াল মেশিনটি একটি নিক্ষেপ করে OutOfMemoryError

সুতরাং, এটি অবজেক্টের বরাদ্দ করার আগে একটি গণনা করে।


যা ঘটে তা হ'ল জেভিএম মেমরিতে স্থায়ী জেনারেশন অঞ্চল (বা পার্মস্পেস) নামক কোনও বস্তুর জন্য মেমরি বরাদ্দ করার চেষ্টা করে। যদি বরাদ্দ ব্যর্থ হয় (এমনকি জেভিএম আবর্জনা সংগ্রাহককে বিনামূল্যে স্থান বরাদ্দের চেষ্টা ও বরাদ্দ দেওয়ার জন্য অনুরোধ করে), এটি একটি নিক্ষেপ করে OutOfMemoryError। এমনকি ব্যতিক্রমগুলির জন্য একটি মেমরির জায়গা প্রয়োজন তাই ত্রুটিটি অনির্দিষ্টকালের জন্য নিক্ষেপ করা হবে।

আরও পড়া. ? অধিকন্তু, OutOfMemoryErrorবিভিন্ন ঘটতে পারে জেভিএম কাঠামো।


10
আমি হ্যাঁ বলতে চাইছি, তবে জাভা ভার্চুয়াল মেশিনের কোনও আউটআফমিউরিওর ফেলে দেওয়ার জন্যও মেমরির প্রয়োজন হবে না? যখন কোনও ওওএম নিক্ষেপ করার স্মৃতি নেই তখন কী ঘটে?
পেসিয়ার

5
তবে যদি জেভিএম কোনও ওওমের একই উদাহরণে রেফারেন্সটি না ফেরায়, আপনি কি সম্মত হন না যে অবশেষে এটির সংরক্ষিত মেমরিটি শেষ হয়ে যাবে? (প্রশ্নের
কোডটিতে

1
: আমাকে এখানে গ্রাহাম এর মন্তব্যের একটি রেফারেন্স করা করার অনুমতি দিন stackoverflow.com/questions/9261705/...
Pacerier

2
চরম মামলার বিবরণে এবং পারমাণবিক বিদ্যুৎকেন্দ্রটিতে ভিএম যদি ওওএম ব্যতিক্রমের একটি সিঙ্গলটন ধরে রাখে তবে খুব সুন্দর হতে পারে।
জন কে

8
@ জনক: আমি আশা করব যে জাভাতে পারমাণবিক বিদ্যুৎকেন্দ্রগুলি প্রোগ্রাম করা হয়নি, ঠিক তেমনই জাভাতে স্পেস শাটল এবং বোয়িং 757 এর প্রোগ্রাম করা হয়নি।
ডায়েটারিচ এপ্প

64

গ্রাহাম বোরল্যান্ড সঠিক বলে মনে হচ্ছে : কমপক্ষে আমার জেভিএম দৃশ্যত আউটআফমিউরিয়রটিগুলি পুনরায় ব্যবহার করে। এটি পরীক্ষা করতে, আমি একটি সাধারণ পরীক্ষা প্রোগ্রাম লিখেছিলাম:

class OOMTest {
    private static void test (OutOfMemoryError o) {
        try {
            for (int n = 1; true; n += n) {
                int[] foo = new int[n];
            }
        } catch (OutOfMemoryError e) {
            if (e == o)
                System.out.println("Got the same OutOfMemoryError twice: " + e);
            else test(e);
        }
    }
    public static void main (String[] args) {
        test(null);
    }
}

এটি চালানো এই আউটপুট উত্পাদন করে:

$ javac OOMTest.java && java -Xmx10m OOMTest 
Got the same OutOfMemoryError twice: java.lang.OutOfMemoryError: Java heap space

বিটিডাব্লু, আমি যে জেভিএম চালাচ্ছি (উবুন্টু 10.04 এ) এটি হ'ল:

$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)

সম্পাদনা: আমি যদি নীচের প্রোগ্রামটি ব্যবহার করে জেভিএমকে পুরোপুরি স্মৃতি থেকে চালাতে বাধ্য করি তবে কী হবে তা দেখার চেষ্টা করেছি :

class OOMTest2 {
    private static void test (int n) {
        int[] foo;
        try {
            foo = new int[n];
            test(n * 2);
        }
        catch (OutOfMemoryError e) {
            test((n+1) / 2);
        }
    }
    public static void main (String[] args) {
        test(1);
    }
}

এটি পরিণত হিসাবে, এটি চিরকালের জন্য লুপ বলে মনে হচ্ছে। তবে, কৌতূহলপূর্ণভাবে, Ctrl+ দিয়ে প্রোগ্রামটি শেষ করার চেষ্টা করা কার্যকর Cহয় না, তবে কেবল নিম্নলিখিত বার্তাটি দেয়:

Java HotSpot(TM) 64-Bit Server VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGINT to handler- the VM may need to be forcibly terminated


চমৎকার পরীক্ষা, সংস্করণ "1.7.0_01" সহ আমার কাছে একই "জাভা হটস্পট (টিএম) 64-বিট সার্ভার ভিএম
পেসারিয়ার

মজাদার. এটি দেখে মনে হচ্ছে যে জেভিএম সম্পূর্ণরূপে লেজ পুনরাবৃত্তি বুঝতে পারে না ... (যেন এটি কিছু লেজ-পুনরাবৃত্ত স্ট্যাক পুনরায় ব্যবহার করছে তবে সমস্ত স্মৃতি পরিষ্কার করার পক্ষে যথেষ্ট নয় ...)
ইজকাটা

আমি কয়টি ভিন্ন পাই তা দেখতে আপনার কোডটি সংশোধন করেছিলাম - আমি সর্বদা অন্য শাখাটি ঠিক 5 বার সম্পাদন করি।
ইরফি

@ ইজকাটা: আমি বরং বলব যে nওওএমগুলি প্রাক-বরাদ্দ করা এবং এর মধ্যে একটির পুনরায় ব্যবহার করার একটি সচেতন সিদ্ধান্ত , যাতে কোনও ওওএম সর্বদা নিক্ষেপ করা যায়। সান / ওরাকলসের জেভিএম মোটামুটি আইআইআরসি তে টেল রিকার্সন সমর্থন করে না?
ইরফি

10
@ ইজকাটা লুপটি আপাতদৃষ্টিতে অন্তহীনভাবে চলছে কারণ জেভিএম স্মৃতিশক্তি শেষ হয়ে যাওয়ার পরে জেএমএম ক্রমাগতভাবে একটি এবং একই (5 তম বা তত) ওম ছুড়ছে। সুতরাং এটি nস্ট্যাকের ফ্রেমগুলি রয়েছে এবং এটি n+1চিরন্তন ফ্রেম তৈরি এবং ধ্বংস করে শেষ করে , অবিরাম চলমান চেহারা দেয়।
ইরফি

41

বেশিরভাগ রানটাইম এনভায়রনমেন্টগুলি প্রারম্ভকালে প্রাক-বরাদ্দ করা হবে, বা অন্যথায় সংরক্ষণ করা হবে, মেমরি অনাহারের পরিস্থিতি মোকাবেলার জন্য পর্যাপ্ত মেমরি। আমি ভাবছি বেশিরভাগ বুদ্ধিমান জেভিএম বাস্তবায়ন এটি করবে।


1
stackoverflow.com/questions/9261215/… : সত্য তবে জেভিএম যদি তা করতে 100 টি ইউনিট মেমরি সংরক্ষণ করে এবং প্রথম ওওমে 1 টি ইউনিট ব্যয় করে, তবে আমার ওওএম ক্যাচ ব্লকে আমি ই .প্রিন্টস্ট্যাকট্রেস () করলে কি হবে? ই.প্রিন্টস্ট্যাকট্রেস () এর জন্যও স্মৃতিশক্তি দরকার। তারপরে জেভিএম আমাকে অন্য ওওএম (98 ইউনিট বাম) ফেলে দেওয়ার জন্য মেমোরির অন্য এককটি ব্যয় করবে এবং আমি এটি একটি প্রিন্টস্ট্যাকট্রেস () দিয়ে ধরলাম যাতে জেভিএম আমাকে অন্য ওওএম (97 ইউনিট বামে) ফেলে দেয় এবং এটি ভালভাবে ধরা পড়েছিল এবং আমি চেয়েছিলাম ..
পেসারিয়ার

3
ঠিক এই কারণেই ওওম কখনও স্ট্যাক ট্রেস অন্তর্ভুক্ত করত না - স্ট্যাক ট্রেসগুলি মেমরি নেয়! ওওম কেবল জাভা 6 ( ব্লগস.অরাকল . com / ্যালান্ব / এন্ট্রি /… ) এ স্ট্যাক ট্রেস অন্তর্ভুক্ত করার চেষ্টা শুরু করে । আমি ধরে নিয়েছি যে যদি স্ট্যাকের ট্রেস সম্ভব না হয় তবে ব্যতিক্রম স্ট্যাক ট্রেস ছাড়াই নিক্ষেপ করা হবে।
শন রিলি

1
@ সানরিলি আমার অর্থ একটি ব্যতিক্রম যেখানে স্ট্যাক ট্রেস নেই তা এখনও একটি অবজেক্ট, যার এখনও স্মৃতি দরকার। স্ট্যাক ট্রেস সরবরাহ করা আছে কিনা তা বিবেচনা না করেই মেমোরির প্রয়োজন। এটা কি সত্য যে ক্যাচ ব্লকে যদি কোনও ওওএম তৈরি করতে কোনও স্মৃতি অবশিষ্ট থাকে না (স্ট্যাক ট্রেস ছাড়াই এমনকি কোনওটি তৈরি করার কোনও স্মৃতি নেই), তবে আমি একটি নাল ধরব?
পেসারিয়ার

17
JVM OOM ব্যতিক্রমের একক স্থিতিক উদাহরণটিতে একাধিক উল্লেখগুলি ফিরিয়ে দিতে পারে। এমনকি যদি আপনার catchধারাটি আরও মেমরি ব্যবহার করার চেষ্টা করে, JVM কেবল একই OOM উদাহরণটি বার বার ছুঁড়ে ফেলে রাখতে পারে।
গ্রাহাম বোরল্যান্ড

1
@TheEliteGentleman আমি সম্মত হই যে এগুলিও খুব ভাল উত্তর, তবে জেভিএম একটি শারীরিক মেশিনে বেঁচে থাকে, এই উত্তরগুলি ব্যাখ্যা করে না যে কীভাবে জেভিএম যাদুতে সর্বদা ওওমের একটি উদাহরণ সরবরাহ করতে পর্যাপ্ত মেমরি রাখতে পারে। "এটি সর্বদা একই উদাহরণ" মনে হয় ধাঁধাটি সমাধান করে solve
পেসারিয়ার

23

গতবার আমি জাভাতে কাজ করছি এবং একটি ডিবাগার ব্যবহার করার সময়, হিপ পরিদর্শক দেখিয়েছিলেন যে JVM প্রারম্ভকালে আউটআফমিউরিরির একটি উদাহরণ বরাদ্দ করেছে। অন্য কথায়, আপনার প্রোগ্রামটি গ্রাস করা শুরু করার আগে, স্মৃতিশক্তিটি একা হয়ে যায় before


12

জেভিএম স্পেক, অধ্যায় 3.5.2 থেকে:

জাভা ভার্চুয়াল মেশিন স্ট্যাকগুলি যদি গতিশীলভাবে প্রসারিত করা যায়, এবং প্রসারণের চেষ্টা করা হয় তবে সম্প্রসারণের প্রভাবের জন্য অপর্যাপ্ত মেমরি উপলব্ধ করা যায়, বা যদি নতুন থ্রেডের জন্য প্রাথমিক জাভা ভার্চুয়াল মেশিন স্ট্যাক তৈরি করার জন্য অপর্যাপ্ত মেমরি উপলব্ধ করা যায় তবে জাভা ভার্চুয়াল মেশিন নিক্ষেপ একটিOutOfMemoryError

প্রতিটি জাভা ভার্চুয়াল মেশিনকে গ্যারান্টি দিতে হবে যে এটি একটি নিক্ষেপ করবে OutOfMemoryError। এর দ্বারা বোঝা যাচ্ছে যে OutOfMemoryErrorকোনও গাদা জায়গা না থাকলেও এটির (বা আগে থেকেই তৈরি করা) উদাহরণ তৈরি করতে সক্ষম হতে হবে ।

যদিও এটির কোনও গ্যারান্টি নেই, এটি ধরতে এবং একটি সুন্দর স্ট্যাকট্রেস মুদ্রণের জন্য পর্যাপ্ত স্মৃতি রয়ে গেছে ...

যোগ

আপনি দেখানোর জন্য কিছু কোড যুক্ত করেছেন, এটিতে যদি একাধিক নিক্ষেপ করতে হয় তবে জেভিএম হ্যাপ স্পেসের বাইরে চলে যেতে পারে OutOfMemoryError। তবে এ জাতীয় বাস্তবায়ন উপরের থেকে প্রয়োজনীয়তা লঙ্ঘন করবে।

কোনও প্রয়োজন নেই যে নিক্ষিপ্ত দৃষ্টান্তগুলি OutOfMemoryErrorঅনন্য বা চাহিদা অনুসারে তৈরি হয়। কোনও জেভিএম OutOfMemoryErrorস্টার্টআপের সময় ঠিক একটি উদাহরণ প্রস্তুত করতে পারে এবং যখনই এটি গাদা জায়গার বাইরে চলে যায় - যা স্বাভাবিক পরিবেশে একবার হয়। অন্য কথায়: OutOfMemoryErrorআমরা দেখতে পাই যে উদাহরণটি সিঙ্গলটন হতে পারে।


আমার ধারণা এটি বাস্তবায়নের জন্য এটি স্থানটি শক্ত থাকলে, স্ট্যাক-ট্রেস রেকর্ড করা থেকে বিরত থাকতে হবে।
রায়েডওয়াল্ড

@ রেয়েডওয়াল্ড: সত্যিকার অর্থে, ওরাকল ভিএম এটিই করেন, আমার উত্তর দেখুন।
স্লেসকে

11

আকর্ষণীয় প্রশ্ন :-)। যদিও অন্যেরা তাত্ত্বিক দিকগুলির ভাল ব্যাখ্যা দিয়েছেন, আমি এটি চেষ্টা করার সিদ্ধান্ত নিয়েছি। এটি ওরাকল জেডিকে 1.6.0_26, উইন্ডোজ 7 64 বিটে রয়েছে।

পরীক্ষা সেটআপ

আমি স্মৃতি থেকে বেরিয়ে আসার জন্য একটি সহজ প্রোগ্রাম লিখেছি (নীচে দেখুন)।

প্রোগ্রামটি কেবল একটি স্ট্যাটিক তৈরি করে java.util.Listএবং ওওএম নিক্ষেপ না করা পর্যন্ত এটিতে নতুন স্ট্রিংগুলি স্টফিং করে রাখে। এটি তখন এটি ধরে এবং একটি অন্তহীন লুপে ভরাট করা চালিয়ে যায় (দরিদ্র জেভিএম ...)।

পরীক্ষার ফলাফল

যেমন কেউ আউটপুট থেকে দেখতে পাচ্ছে, প্রথম চার বার ওওম নিক্ষেপ করা হয়েছে, এটি স্ট্যাক ট্রেস নিয়ে আসে। তারপরে, পরবর্তী ওওমগুলি কেবল অনুরোধ করা java.lang.OutOfMemoryError: Java heap spaceহলে মুদ্রণ করে printStackTrace()

সুতরাং স্পষ্টতই JVM স্ট্যাক ট্রেস যদি এটি করতে পারে তবে মুদ্রণের জন্য চেষ্টা করে তবে মেমরিটি যদি সত্যিই আঁটসাঁট থাকে তবে অন্যান্য উত্তরগুলির মতো এটি কেবল ট্রেসকে বাদ দেয়।

এছাড়াও আকর্ষণীয় হ'ল ওওমের হ্যাশ কোড। মনে রাখবেন যে প্রথম কয়েকটি ওওমের সবার আলাদা আলাদা হ্যাশ রয়েছে। একবার জেভিএম স্ট্যাকের চিহ্নগুলি বাদ দিতে শুরু করলে হ্যাশ সর্বদা একই থাকে। এটি পরামর্শ দেয় যে JVM যতক্ষণ সম্ভব তত্কালীন (পূর্বনির্ধারিত?) উদাহরণ ব্যবহার করবে তবে ধাক্কাটি যদি আসে তবে এটি ছুঁড়ে দেওয়ার মতো কিছু না রেখে কেবল একই উদাহরণটি পুনরায় ব্যবহার করবে।

আউটপুট

দ্রষ্টব্য: আউটপুটটি পড়ার জন্য সহজ করার জন্য আমি কিছু স্ট্যাকের চিহ্ন ছাঁটা করেছি ("[...]")।

iteration 0
iteration 100000
iteration 200000
iteration 300000
iteration 400000
iteration 500000
iteration 600000
iteration 700000
iteration 800000
iteration 900000
iteration 1000000
iteration 1100000
iteration 1200000
iteration 1300000
iteration 1400000
iteration 1500000
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1069480624
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.ArrayList.ensureCapacity(Unknown Source)
    at java.util.ArrayList.add(Unknown Source)
    at testsl.Div.gobbleUpMemory(Div.java:23)
    at testsl.Div.exhaustMemory(Div.java:12)
    at testsl.Div.main(Div.java:7)
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
[...]
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 616699029
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
[...]
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 2136955031
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
[...]
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1535562945
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1734048134
Keep on trying...
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1734048134
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1734048134
Keep on trying...
[...]

কার্যক্রম

public class Div{
    static java.util.List<String> list = new java.util.ArrayList<String>();

    public static void main(String[] args) {
        exhaustMemory();
    }

    private static void exhaustMemory() {
        try {
            gobbleUpMemory();
        } catch (OutOfMemoryError e) {
            System.out.println("Ouch: " + e+"; hash: "+e.hashCode());
            e.printStackTrace();
            System.out.println("Keep on trying...");
            exhaustMemory();
        }
    }

    private static void gobbleUpMemory() {
        for (int i = 0; i < 10000000; i++) {
            list.add(new String("some random long string; use constructor to force new instance"));
            if (i % 10000000== 0) {
                System.out.println("iteration "+i);
            }
        }

    }
}

যখন ধাক্কা টানতে আসে, এটি ওওমের জন্য মেমরির বরাদ্দ করতে পারে না, সুতরাং এটি ইতিমধ্যে তৈরি করাগুলিকে ফ্লাশ করে।
বুহাকে সিন্ধি

1
মাইনর নোট: আপনার কিছু আউটপুট অনুক্রমের বাইরে চলেছে বলে মনে হচ্ছে সম্ভবত আপনি মুদ্রণ করছেন System.outতবে ডিফল্টরূপে printStackTrace()ব্যবহার করছেন System.err। ধারাবাহিকভাবে দুটি স্ট্রিম ব্যবহার করে আপনি সম্ভবত আরও ভাল ফলাফল পেতে চাইবেন।
ইলমারি করোনেন

@ ইলমারি কারোনেন: হ্যাঁ, আমি এটি লক্ষ্য করেছি। এটি কেবল একটি উদাহরণ, তাই এটি কোনও ব্যাপার নয়। স্পষ্টতই আপনি এটি উত্পাদন কোড ব্যবহার করবেন না।
সেলসেকে

সত্য, আমি প্রথম যখন আউটপুটটি দেখলাম তখন **** কী চলছে তা নির্ধারণ করতে আমাকে কিছুটা সময় নিয়েছিল।
ইলমারি করোনেন

6

আমি বেশ নিশ্চিত, জেভিএম একেবারে নিশ্চিত করে নিবে যে এটির স্মৃতিশক্তি ফুরিয়ে যাওয়ার আগে এটির ব্যতিক্রম ছড়িয়ে দেওয়ার জন্য কমপক্ষে পর্যাপ্ত মেমরি রয়েছে।


1
কিন্তু তারা কোন ব্যাপার কত স্মৃতি সংরক্ষিত এই অবস্থায় আঘাত করবে stackoverflow.com/questions/9261705/...
Pacerier

4

একটি পরিচালিত-মেমরি পরিবেশের সীমানা লঙ্ঘনের প্রয়াসকে চিহ্নিত ব্যতিক্রমগুলি এই ক্ষেত্রে জেভিএমের রানটাইম দ্বারা পরিচালিত হয়। জেভিএম এর নিজস্ব প্রক্রিয়া যা আপনার অ্যাপ্লিকেশনটির আইএল চালাচ্ছে। কোনও প্রোগ্রাম যদি কল করার চেষ্টা করে যা কল স্ট্যাককে সীমা ছাড়িয়ে যায়, বা JVM রিজার্ভ করতে পারে তার চেয়ে বেশি মেমরি বরাদ্দ করে, রানটাইম নিজেই একটি ব্যতিক্রম ইনজেকশনের ব্যবস্থা করে, যার ফলে কল স্ট্যাকটি বন্ধ হয়ে যায়। আপনার প্রোগ্রামটি বর্তমানে কত পরিমাণে মেমরির প্রয়োজন তা বিবেচনা না করেই, বা এর কল স্ট্যাকের গভীরতা কতটুকু হোক না কেন, জেভিএম ব্যতিক্রমটি তৈরি করতে এবং এটি আপনার কোডে ইনজেক্ট করার জন্য তার নিজস্ব প্রসেসের সীমানার মধ্যে পর্যাপ্ত মেমরি বরাদ্দ করবে।


"জেভিএম তার নিজস্ব প্রসেসের মধ্যে পর্যাপ্ত মেমরি বরাদ্দ করবে ব্যতিক্রমটি তৈরি করার জন্য বলেছে" তবে যদি আপনার কোডটি সেই ব্যতিক্রমের কোনও রেফারেন্স ধরে রাখে, তবে এটি পুনরায় ব্যবহার করা যাবে না, কীভাবে এটি অন্যটি তৈরি করতে পারে? বা আপনি কি এটির একটি বিশেষ সিঙ্গেলটন ওওম অবজেক্ট রাখার পরামর্শ দিচ্ছেন?
রায়েডওয়াল্ড

আমি এটা পরামর্শ দিচ্ছি না। যদি আপনার প্রোগ্রামটি জেভিএম বা ওএস দ্বারা তৈরি এবং ইনজেকশনযুক্ত তৈরি হওয়া ব্যতীত কখনও তৈরি হওয়া প্রতিটি ব্যতিক্রমকে আটকে রাখে এবং অবশেষে জেভিএম নিজেই ওএস দ্বারা নির্ধারিত কিছু সীমানা ছাড়িয়ে যাবে এবং ওএস এটি জিপিএফ বা বন্ধ করে দেবে বা অনুরূপ ত্রুটি তবে, এটি প্রথম স্থানে খারাপ নকশা; ব্যতিক্রম হয় হয় পরিচালনা করা উচিত এবং তারপরে সুযোগের বাইরে চলে যেতে হবে, বা ফেলে দেওয়া উচিত। এবং আপনার কোনও এসওই বা ওওমকে ধরতে এবং চালিয়ে যাওয়ার চেষ্টা করা উচিত নয়; "সাফাই" ব্যতীত অন্যটি যাতে আপনি কৃপণভাবে প্রস্থান করতে পারেন, এই পরিস্থিতিতে মৃত্যুদন্ড কার্যকর করতে আপনি যা করতে পারেন তা কিছুই নেই।
কিথস

"এটি প্রথম স্থানে খারাপ নকশা": ভয়ানক নকশা। কিন্তু প্যাড্যান্টিক্যালি, জেভিএম যদি সেই পদ্ধতিতে ব্যর্থ হয় তবে স্পেসিফিকেশনটির সাথে সামঞ্জস্য করবে?
রায়েডওয়াল্ড

4

আপনি জেভিএম দ্বারা সংরক্ষিত ভার্চুয়াল মেমরিটিকে বিভ্রান্ত করছেন বলে মনে হচ্ছে যেখানে জেভিএম হোস্ট ওএসের নেটিভ মেমরির সাথে জাভা প্রোগ্রামগুলি চালায় যা জেভিএম একটি দেশীয় প্রক্রিয়া হিসাবে চালিত হয়। আপনার মেশিনের জেভিএম ওএস দ্বারা পরিচালিত মেমরিতে চলছে, মেমরিতে নয় জেভিএম জাভা প্রোগ্রামগুলি চালনার জন্য সংরক্ষণ করেছে।

আরও পড়া:

এবং একটি চূড়ান্ত নোট হিসাবে, একটি স্ট্যাকট্রেস মুদ্রণের জন্য java.lang.Error (এবং এর বংশধর শ্রেণিগুলি) ধরার চেষ্টা করা আপনাকে কোনও দরকারী তথ্য নাও দিতে পারে। পরিবর্তে আপনি হিপ ডাম্প চান।


4

কার্যক্রমে @ গ্রাহাম বোরল্যান্ডের উত্তরটি আরও স্পষ্ট করতে, জেভিএম প্রারম্ভকালে এটি করে:

private static final OutOfMemoryError OOME = new OutOfMemoryError();

পরে, জেভিএম নীচের একটি জাভা বাইটোকডগুলি কার্যকর করে: 'নতুন', 'আনোয়ারে', বা 'মাল্টিনেয়ারে'। এই নির্দেশের ফলে জেভিএম মেমরির বাইরে থাকা অবস্থায় বিভিন্ন পদক্ষেপ সম্পাদন করে:

  1. একটি নেটিভ ফাংশন জিজ্ঞাসা করুন, বলুন allocate()allocate()নির্দিষ্ট শ্রেণি বা অ্যারের কয়েকটি নতুন ইভেন্টের জন্য মেমরি বরাদ্দ করার চেষ্টা করে।
  2. এই বরাদ্দের অনুরোধ ব্যর্থ হয়েছে, সুতরাং জেভিএম আরেকটি নেটিভ ফাংশনটি আহ্বান করে, বলুন doGC(), যা আবর্জনা সংগ্রহের চেষ্টা করে।
  3. যখন ফাংশনটি ফিরে আসে, allocate()আবার একবারের জন্য মেমরি বরাদ্দ করার চেষ্টা করে।
  4. যদি এটি (*) ব্যর্থ হয়, তবে জেভিএম, বরাদ্দ () এর মধ্যে কেবল একটি করে throw OOME;, ওআউমে উল্লেখ করে যা এটি প্রারম্ভের সময় ইনস্ট্যান্ট করেছিল। মনে রাখবেন যে এটির জন্য O Oome বরাদ্দ করতে হয়নি, এটি কেবল এটি উল্লেখ করে।

স্পষ্টতই, এগুলি আক্ষরিক পদক্ষেপ নয়; বাস্তবায়নে এগুলি জেভিএম থেকে জেভিএম-তে পরিবর্তিত হবে তবে এটি উচ্চ-স্তরের ধারণা।

(*) ব্যর্থ হওয়ার আগে এখানে উল্লেখযোগ্য পরিমাণে কাজ ঘটে। জেভিএম সফটরিফারেন্স অবজেক্টগুলি সাফ করার চেষ্টা করবে, প্রজন্মের সংগ্রাহক ব্যবহার করার সময় সরাসরি টেনার প্রজন্মের মধ্যে বরাদ্দ দেওয়ার চেষ্টা করবে এবং সম্ভবত চূড়ান্তকরণের মতো অন্যান্য জিনিস।


3

যে উত্তরগুলি বলে যে জেভিএম প্রাক-বরাদ্দ করবে OutOfMemoryErrorsতা সত্যই সঠিক।
স্মৃতি ছাড়িয়ে যাওয়া পরিস্থিতিকে উস্কে দিয়ে আমরা এটি পরীক্ষার পাশাপাশি আমরা যে কোনও জেভিএমের হিপটি পরীক্ষা করতে পারি (আমি একটি ছোট প্রোগ্রাম ব্যবহার করেছি যা জাভা 8 আপডেট 31 থেকে ওরাকলের হটস্পট জেভিএম ব্যবহার করে এটি চালায়) just

ব্যবহার করে jmapআমরা দেখতে পেলাম যে আউটআফমিউরিওরির 9 টি উদাহরণ রয়েছে (যদিও আমাদের প্রচুর স্মৃতি রয়েছে):

> jmap -histo 12103 | গ্রেপ আউট অফ মেমরিরির
 71: 9 288 java.lang.OutOfMemoryError
170: 1 32 [লাজভা.এলং.আউটআউফ মেমরিরির;

তারপরে আমরা একটি হিপ ডাম্প তৈরি করতে পারি:

> jmap -dump: ফর্ম্যাট = বি, ফাইল = হিপ

এবং এ্যাক্লিপস মেমরি অ্যানালাইজার ব্যবহার করে এটি খুলুন , যেখানে একটি ওকিউএল কোয়েরি দেখায় যে জেভিএম আসলে OutOfMemoryErrorsসমস্ত সম্ভাব্য বার্তাগুলির জন্য প্রাক-বরাদ্দ করেছে:

এখানে চিত্র বর্ণনা লিখুন

জাভা 8 হটস্পট জেভিএম এর কোড যা প্রকৃতপক্ষে এগুলি পূর্বনির্ধারিত করে তা এখানে পাওয়া যাবে এবং দেখতে এটির (দেখতে কিছু অংশ বাদে) পাওয়া যাবে:

...
// Setup preallocated OutOfMemoryError errors
k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_OutOfMemoryError(), true, CHECK_false);
k_h = instanceKlassHandle(THREAD, k);
Universe::_out_of_memory_error_java_heap = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_metaspace = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_class_metaspace = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_array_size = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_gc_overhead_limit =
  k_h->allocate_instance(CHECK_false);

...

if (!DumpSharedSpaces) {
  // These are the only Java fields that are currently set during shared space dumping.
  // We prefer to not handle this generally, so we always reinitialize these detail messages.
  Handle msg = java_lang_String::create_from_str("Java heap space", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_java_heap, msg());

  msg = java_lang_String::create_from_str("Metaspace", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_metaspace, msg());
  msg = java_lang_String::create_from_str("Compressed class space", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_class_metaspace, msg());

  msg = java_lang_String::create_from_str("Requested array size exceeds VM limit", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_array_size, msg());

  msg = java_lang_String::create_from_str("GC overhead limit exceeded", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_gc_overhead_limit, msg());

  msg = java_lang_String::create_from_str("/ by zero", CHECK_false);
  java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg());

  // Setup the array of errors that have preallocated backtrace
  k = Universe::_out_of_memory_error_java_heap->klass();
  assert(k->name() == vmSymbols::java_lang_OutOfMemoryError(), "should be out of memory error");
  k_h = instanceKlassHandle(THREAD, k);

  int len = (StackTraceInThrowable) ? (int)PreallocatedOutOfMemoryErrorCount : 0;
  Universe::_preallocated_out_of_memory_error_array = oopFactory::new_objArray(k_h(), len, CHECK_false);
  for (int i=0; i<len; i++) {
    oop err = k_h->allocate_instance(CHECK_false);
    Handle err_h = Handle(THREAD, err);
    java_lang_Throwable::allocate_backtrace(err_h, CHECK_false);
    Universe::preallocated_out_of_memory_errors()->obj_at_put(i, err_h());
  }
  Universe::_preallocated_out_of_memory_error_avail_count = (jint)len;
}
...

এবং এই কোডটি দেখায় যে জেভিএম প্রথমে স্ট্যাক ট্রেসের জন্য স্থানের সাথে পূর্ব নির্ধারিত ত্রুটিগুলির একটি ব্যবহার করার চেষ্টা করবে এবং তারপরে স্ট্যাক ট্রেস ছাড়াই একটিতে ফিরে যাবে:

oop Universe::gen_out_of_memory_error(oop default_err) {
  // generate an out of memory error:
  // - if there is a preallocated error with backtrace available then return it wth
  //   a filled in stack trace.
  // - if there are no preallocated errors with backtrace available then return
  //   an error without backtrace.
  int next;
  if (_preallocated_out_of_memory_error_avail_count > 0) {
    next = (int)Atomic::add(-1, &_preallocated_out_of_memory_error_avail_count);
    assert(next < (int)PreallocatedOutOfMemoryErrorCount, "avail count is corrupt");
  } else {
    next = -1;
  }
  if (next < 0) {
    // all preallocated errors have been used.
    // return default
    return default_err;
  } else {
    // get the error object at the slot and set set it to NULL so that the
    // array isn't keeping it alive anymore.
    oop exc = preallocated_out_of_memory_errors()->obj_at(next);
    assert(exc != NULL, "slot has been used already");
    preallocated_out_of_memory_errors()->obj_at_put(next, NULL);

    // use the message from the default error
    oop msg = java_lang_Throwable::message(default_err);
    assert(msg != NULL, "no message");
    java_lang_Throwable::set_message(exc, msg);

    // populate the stack trace and return it.
    java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(exc);
    return exc;
  }
}

ভাল পোস্ট, আমি আগের সপ্তাহে ফিরে যাওয়ার আগে আরও দৃশ্যমানতা দেওয়ার জন্য এটি এক সপ্তাহের জন্য উত্তর হিসাবে গ্রহণ করব।
পেসেরিয়র

জাভা 8 এবং উচ্চতর স্থায়ী জেনারেশন স্পেস পুরোপুরি সরিয়ে দেওয়া হয়েছে এবং আপনি জাভা 8 থেকে উচ্চতর স্থান বরাদ্দ মেমরির আকার নির্দিষ্ট করতে পারবেন না যেহেতু তারা ডায়নামিক ক্লাস মেটাডেটা মেমরি পরিচালনা ডেকেছে Metaspace। এটি খুব ভাল হবে যদি আপনি এমন কোনও কোড প্রদর্শন করতে পারেন যা পার্মজেনের জন্যও সরবরাহ করে এবং এটি মেটাস্পেসের সাথেও তুলনা করে।
বুহাকে সিন্ধি 25'15

@ বুহাকসিন্ডি - স্থায়ী প্রজন্মের এর সাথে কী করার আছে তা আমি দেখতে পাচ্ছি না। আপনি নিজের উত্তরে উল্লেখ করার সাথে স্থায়ী জেনারেশনে নতুন অবজেক্ট বরাদ্দ করা হয় না। আপনি কখনই এই ঘটনাটি উল্লেখ করেননি যে আউটঅফমিউরিইরিজগুলি প্রাক বরাদ্দযুক্ত (যা প্রশ্নের আসল উত্তর)।
জোহান কাভিং

1
ঠিক আছে, আমি যা বলছি তা জাভা 8 থেকে, অবজেক্টের বরাদ্দকে গতিশীলভাবে গণনা করা হয় যখন এটি পূর্বনির্ধারিত হিপ স্থানের জন্য বরাদ্দ দেওয়ার আগে, সম্ভবত এটি প্রাক-বরাদ্দ আগেই। যদিও ওওম প্রাক-বরাদ্দ করা হয়েছে, সেখানে ওওমকে নিক্ষেপ করা দরকার কিনা তা নির্ধারণের জন্য "গণনা" করা হয়েছে (সুতরাং আমি জেএলএসের স্পেসিফিকেশনের উল্লেখ কেন করছি)।
বুহাকে সিন্ধি

1
জাভা হ্যাপের আকারটি আগের মতো জাভা 8-তে পূর্বনির্ধারিত। স্থায়ী জেনারেশন হিপগুলির অংশ ছিল যা ক্লাস মেটা-ডেটা, ইন্টার্নড স্ট্রিংস এবং ক্লাস স্ট্যাটিক্স ধারণ করে। এটির একটি সীমিত আকার ছিল যা মোট apੇਰ আকারের থেকে আলাদা করে সুর করা দরকার। জাভা 8-এ ক্লাসের মেটা-ডেটা দেশীয় মেমোরিতে স্থানান্তরিত হয়েছে এবং অভ্যন্তরীণ স্ট্রিংগুলি এবং শ্রেণীর স্ট্যাটিকসগুলি নিয়মিত জাভা হিপগুলিতে স্থানান্তরিত করা হয়েছে (উদাহরণস্বরূপ এখানে দেখুন: infoq.com/articles/ জাভা- পারমজেন-সরিয়ে নেওয়া )।
জোহান কাভিং 26'15
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.