জাভা.এলং.আউটওফ মেমরিরির ধরা?


102

বলার জন্য ডকুমেন্টেশনjava.lang.Error :

একটি ত্রুটি থ্রোয়েবলের একটি সাবক্লাস যা গুরুতর সমস্যাগুলি নির্দেশ করে যা যুক্তিসঙ্গত প্রয়োগটি ধরার চেষ্টা করা উচিত নয়

তবে java.lang.Errorএকটি সাবক্লাস হিসাবে java.lang.Throwable, আমি থ্রোয়েবল এই ধরণের ধরতে পারি।

আমি বুঝতে পারি কেন এই ধরণের ব্যতিক্রম ধরা ভাল ধারণা নয়। আমি যতদূর বুঝতে পারি, যদি আমরা এটি ধরার সিদ্ধান্ত নিই, তবে ক্যাচ হ্যান্ডলারের কোনও মেমরি নিজে থেকে বরাদ্দ করা উচিত নয়। নইলে OutOfMemoryErrorআবার ফেলে দেওয়া হবে।

সুতরাং, আমার প্রশ্নটি হ'ল:

  1. আকর্ষণীয় java.lang.OutOfMemoryErrorধারণা থাকতে পারে এমন কোনও বাস্তব বিশ্বের পরিস্থিতি আছে কি?
  2. যদি আমরা ধরার সিদ্ধান্ত নিই java.lang.OutOfMemoryError, আমরা কীভাবে নিশ্চিত করতে পারি যে ক্যাচ হ্যান্ডলার নিজের দ্বারা কোনও স্মৃতি বরাদ্দ করে না (কোনও সরঞ্জাম বা সেরা অনুশীলন)?


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

4
সুনির্দিষ্ট কেস রয়েছে, উদাহরণস্বরূপ, বিশালাকার অ্যারে বরাদ্দ করা, যেখানে কেউ সেই অপারেশনটির চারপাশে OOM ত্রুটিটি ধরতে পারে এবং যুক্তিসঙ্গতভাবে ভালভাবে পুনরুদ্ধার করতে পারে। তবে কোডের একটি বৃহত ব্লবের চারপাশে চেষ্টা / ধরার বিষয়টি এবং পরিষ্কারভাবে পুনরুদ্ধার করার চেষ্টা চালিয়ে যাওয়া সম্ভবত একটি খারাপ ধারণা।
হট লিক্স

উত্তর:


86

এমন অনেকগুলি পরিস্থিতি রয়েছে যেখানে আপনি OutOfMemoryErrorনিজের অভিজ্ঞতাটি ধরতে চাইতে পারেন (উইন্ডোজ এবং সোলারিস জেভিএমগুলিতে), কেবল খুব কমই OutOfMemoryErrorএকটি জেভিএমের কাছে মৃত্যু-পাতন।

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

সাধারণভাবে, OutOfMemoryErrorএকটি ব্লক মেমরি বরাদ্দের কারণে ঘটে যা গাদাটির অবশিষ্ট সংস্থানগুলিতে সন্তুষ্ট হতে পারে না।

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

বিক্ষোভের OutOfMemoryErrorঅর্থ এই নয় যে জেভিএম ক্যাচ ব্লকে স্মৃতি ছাড়িয়ে গেছে:

private static final int MEGABYTE = (1024*1024);
public static void runOutOfMemory() {
    MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
    for (int i=1; i <= 100; i++) {
        try {
            byte[] bytes = new byte[MEGABYTE*500];
        } catch (Exception e) {
            e.printStackTrace();
        } catch (OutOfMemoryError e) {
            MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
            long maxMemory = heapUsage.getMax() / MEGABYTE;
            long usedMemory = heapUsage.getUsed() / MEGABYTE;
            System.out.println(i+ " : Memory Use :" + usedMemory + "M/" +maxMemory+"M");
        }
    }
}

এই কোডের আউটপুট:

1 : Memory Use :0M/247M
..
..
..
98 : Memory Use :0M/247M
99 : Memory Use :0M/247M
100 : Memory Use :0M/247M

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

সাবধানবাণীটি হ'ল আপনাকে কেবল যেখানে পরিষ্কার-পরিচ্ছন্নতা সম্ভব সেখানে এই ধরণের ত্রুটি ধরা লক্ষ্য করতে হবে। কম্বল catch(Throwable t) {}কোথাও বা এই মত বাজে কথা বলবেন না ।


সম্মত হন, আমি আমার উত্তরটি একটি নতুন উত্তরে পোস্ট করব।
মিস্টার স্মিথ

4
"আপনি কখনই 100% নিশ্চিত হতে পারবেন না যে জেভিএম পুনঃস্থাপনযোগ্য অবস্থায় রয়েছে": কারণ OutOfMemoryErrorসম্ভবত এমন একটি বিন্দু থেকে নিক্ষিপ্ত হয়েছে যা আপনাকে প্রোগ্রামটিকে একটি বেমানান অবস্থায় ফেলেছে, কারণ এটি যে কোনও সময় নিক্ষিপ্ত হতে পারে । দেখুন stackoverflow.com/questions/8728866/...
Raedwald

OpenJdk1.7.0_40 এ, এই কোডটি চালানোর সময় আমি কোনও ত্রুটি বা ব্যতিক্রম পাই না। এমনকি আমি মেগাবাইটকে জিগাবাইট (1024 * 1024 * 1024) এ পরিবর্তন করেছি। এটি কি অপ্টিমাইজারের কারণে পরিবর্তনশীল 'বাইট [] বাইটস' অপসারণ করে কারণ এটি বাকী কোডটিতে ব্যবহৃত হয় না?
রোবোক্লেক্স

"এমন অনেকগুলি পরিস্থিতি রয়েছে যেখানে আপনি আউটআফমিউরিওর ধরতে ইচ্ছুক হতে পারেন" বনাম " আউটআফমিউরিওর ধরার জন্য কেবলমাত্র একটি ভাল কারণ আছে" । তোমার মনস্থির কর!!!
স্টিফেন সি

4
রিয়েল-ওয়ার্ল্ডের পরিস্থিতি যখন আপনি আউটআউফ মেমরি ত্রুটি ধরতে চান: যখন এটি 2 জি-র বেশি উপাদানের সাথে অ্যারে বরাদ্দ করার চেষ্টা করে থাকে। ত্রুটির নামটি এই ক্ষেত্রে কিছুটা মিসনোমার হলেও এটি এখনও একটি ওওএম।
চার্লস রথ

31

আপনি এটি থেকে পুনরুদ্ধার করতে পারেন:

package com.stackoverflow.q2679330;

public class Test {

    public static void main(String... args) {
        int size = Integer.MAX_VALUE;
        int factor = 10;

        while (true) {
            try {
                System.out.println("Trying to allocate " + size + " bytes");
                byte[] bytes = new byte[size];
                System.out.println("Succeed!");
                break;
            } catch (OutOfMemoryError e) {
                System.out.println("OOME .. Trying again with 10x less");
                size /= factor;
            }
        }
    }

}

তবে কি তা বোঝা যায়? আপনি আর কি করতে চান? আপনি কেন প্রাথমিকভাবে এত বেশি স্মৃতি বরাদ্দ করবেন? কম স্মৃতিও কি ঠিক আছে? আপনি ইতিমধ্যে যেভাবেই এটি ব্যবহার করছেন না? বা যদি তা সম্ভব না হয় তবে কেন শুরু থেকেই জেভিএমকে আরও মেমরি দিচ্ছেন না?

আপনার প্রশ্নগুলিতে ফিরে যান:

1: java.lang.OutOfMemoryError ধরার সময় কোনও বাস্তব শব্দের পরিস্থিতি আছে কি ভাল ধারণা হতে পারে?

কারও মনে আসে না।

2: যদি আমরা java.lang.OutOfMemoryError ধরছি তবে কীভাবে আমরা নিশ্চিত করতে পারি যে ক্যাচ হ্যান্ডলার নিজের দ্বারা কোনও স্মৃতি বরাদ্দ করে না (কোনও সরঞ্জাম বা সর্বোত্তম অভ্যাস)?

ওউমের কারণ কী হয়েছে তার উপর নির্ভর করে। যদি এটি tryব্লকের বাইরে ঘোষণা করা হয় এবং এটি ধাপে ধাপে ঘটে তবে আপনার সম্ভাবনা খুব কম। আপনি আগে কিছু স্মৃতি স্থান সংরক্ষণ করতে চাইতে পারেন:

private static byte[] reserve = new byte[1024 * 1024]; // Reserves 1MB.

এবং তারপরে এটিকে শূন্যতে সেট করুন:

} catch (OutOfMemoryException e) {
     reserve = new byte[0];
     // Ha! 1MB free!
}

অবশ্যই এটি সমস্ত বুদ্ধি দিয়ে সমস্ত করে তোলে;) আপনার আবেদনের প্রয়োজন হিসাবে কেবল জেভিএমকে পর্যাপ্ত মেমরি দিন। প্রয়োজনে প্রোফাইলার চালান।


4
এমনকি জায়গা সংরক্ষণ করে এটি কোনও কাজের সমাধানের কোনও গ্যারান্টি নেই। সেই স্থানটি অন্য কোনও থ্রেড
দ্বারাও

@ ওল্ফ: তারপরে জেভিএমকে আরও মেমরি দিন! O_o সব দিয়ে এটি আসলেই কোনও বুদ্ধি করে না;)
বালাসসি

4
প্রথম স্নিপেট কাজ করে কারণ যে ত্রুটিটি ট্রিগার করেছিল সেই বস্তুটি একটি একক বিআইজি অবজেক্ট (অ্যারে)। ক্যাচ ক্লজটি পৌঁছে গেলে তা স্মৃতি-ক্ষুধার্ত জেভিএম সংগ্রহ করেছে has আপনি যদি চেষ্টা ব্লকের বাইরে একই জিনিস ব্যবহার করতেন, বা অন্য থ্রেডে বা একই ক্যাচে, জেভিএম এটি সংগ্রহ করে না, এটি কোনও ধরণের নতুন একক অবজেক্ট তৈরি করা অসম্ভব করে তোলে। দ্বিতীয় স্নিপেট উদাহরণস্বরূপ, কাজ নাও করতে পারে।
মিস্টার স্মিথ

4
কেন এটি সেট করে না null?
পেসারিয়ার

4
@ মিস্টারস্মিথ আপনার মন্তব্যটির কোনও অর্থ নেই। বড় বস্তুর অস্তিত্ব নেই। এটি প্রথম স্থানে বরাদ্দ দেওয়া হয়নি: এটি OOMকে ট্রিগার করেছিল, সুতরাং অবশ্যই এটির জন্য জিসির প্রয়োজন নেই।
লার্নের মারকুইস

16

সাধারণভাবে, কোনও ওওএম ধরা এবং পুনরুদ্ধার করার চেষ্টা করা খারাপ ধারণা।

  1. আপনার অ্যাপ্লিকেশন এমনকি জানেন না এমন থ্রেড সহ একটি থিমও অন্য থ্রেডে ফেলে দেওয়া যেতে পারে। এ জাতীয় যে কোনও থ্রেড এখন মারা যাবে এবং কোনও বিজ্ঞপ্তির অপেক্ষায় থাকা যেকোনো কিছু চিরতরে আটকে যেতে পারে। সংক্ষেপে, আপনার অ্যাপ্লিকেশনটি স্থায়ীভাবে ভেঙে যেতে পারে।

  2. এমনকি যদি আপনি সফলভাবে পুনরুদ্ধার করেন তবে আপনার জেভিএম এখনও প্রচুর পরিমাণে অনাহারে ভুগতে পারে এবং ফলস্বরূপ আপনার প্রয়োগ অস্বাভাবিকভাবে সম্পাদন করবে।

ওওমের সাথে করণীয় সর্বোত্তম জিনিস হ'ল জেভিএমকে মরতে দেওয়া।

(এই যে জেভিএম অনুমান করে ডাই। একটি হুল বিড়াল সার্ভলেট থ্রেডে উদাহরণস্বরূপ OOMs জন্য জেভিএম হত্যা করো না, এবং একটি ক্যাটাটোনিক দশায় যাচ্ছে হুল বিড়াল এই বিশালাকার যেখানে এটি কোনো অনুরোধ সাড়া না ... এমনকি অনুরোধ করা হবে না আবার শুরু.)

সম্পাদনা

আমি বলছি না যে ওওএম কে আদৌ ধরা খুব খারাপ ধারণা। সমস্যাগুলি তখন উত্থাপিতভাবে বা তদারকি করে Oome থেকে পুনরুদ্ধার করার চেষ্টা করলে সমস্যা দেখা দেয়। আপনি যখনই কোনও ওওএম ধরেন (সরাসরি, বা ত্রুটির সাব-টাইপ বা থ্রোয়েবল হিসাবে) আপনার উচিত হয় এটি পুনর্বিবেচনা করা উচিত, বা অ্যাপ্লিকেশন / জেভিএম থেকে বেরিয়ে আসার ব্যবস্থা করুন।

একদিকে: এটি পরামর্শ দেয় যে ওওএম-এর মুখের সর্বাধিক দৃust়তার জন্য কোনও অ্যাপ্লিকেশনকে হ্যান্ডলার সেট করতে থ্রেড.সেট ডিফল্টউনকুট এক্সেকশনহ্যান্ডলার () ব্যবহার করা উচিত যা কোনও ওওমের ক্ষেত্রে অ্যাপ্লিকেশনটি প্রস্থান করতে পারে, যাই হোক না কেন ওমেটিকে কোন থ্রেড দেওয়া হয় thrown আমি এই বিষয়ে মতামত আগ্রহী ...

কেবলমাত্র অন্য পরিস্থিতিটি হ'ল যখন আপনি নিশ্চিতভাবেই জানেন যে ওওমের কোনও সমান্তরাল ক্ষতি হয়নি; যেমন আপনি জানেন:

  • বিশেষ করে ওমের কারণ কী?
  • অ্যাপ্লিকেশনটি সেই সময়ে কী করছে এবং কেবল সেই গণনাটি বাতিল করা ঠিক আছে এবং
  • যে (মোটামুটিভাবে) একযোগে ওমেম অন্য থ্রেডে ঘটতে পারে না।

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

(সমস্যাটি হ'ল এটি একটি আনুষ্ঠানিক প্রমাণ দেখাতে হবে যে "প্রত্যাশিত" OOMs এর পরিণামগুলি নিরাপদ, এবং "অপ্রত্যাশিত" ওমোমগুলি চেষ্টা / আউটকে ধরার নিয়ন্ত্রণে আসতে পারে না))


হ্যা আমি আপনার সাথে একমত. সাধারণভাবে, এটি খারাপ ধারণা। তবে কেন আমার এটি ধরার সম্ভাবনা আছে? :)
ডেনিস বাজনোভ

@ডটসিড - ১) কারণ এমন ঘটনা রয়েছে যেখানে আপনার এটি ধরা উচিত এবং ২) কারণ ওওমকে ধরা অসম্ভব করে তোলে তা ভাষা এবং জাভা রানটাইমের অন্যান্য অংশগুলিতে নেতিবাচক প্রভাব ফেলবে।
স্টিফেন সি

4
আপনি বলেছেন: "কারণ এমন ঘটনা আছে যেখানে আপনার এটি ধরা উচিত"। সুতরাং এটি আমার মূল প্রশ্নের অংশ ছিল। আপনি যখন ওমকে ধরতে চান তখন কী কী ঘটনা ঘটে?
ডেনিস বাজনোভ

4
@ ডটসিড - আমার সম্পাদিত উত্তর দেখুন। OOM ধরার জন্য আমি কেবলমাত্র সেই ক্ষেত্রেই ভাবতে পারি যখন আপনি কোনও OOM এর ক্ষেত্রে মাল্টি-থ্রেড অ্যাপ্লিকেশনটি প্রস্থান করার জন্য বাধ্য করতে এটি করার দরকার হয় । আপনি হয়ত সব ধরণের সাব-টাইপের জন্য এটি করতে চান Error
স্টিফেন সি

4
এটি কেবল ওমামকে ধরার বিষয় নয়। আপনার এগুলি থেকে পুনরুদ্ধার করাও দরকার। থ্রেডটি কীভাবে পুনরুদ্ধার হবে যদি এটি বলার (অন্যভাবে) অন্য থ্রেডকে অবহিত করার কথা ছিল ... তবে এটি একটি ওওম পেয়েছে? অবশ্যই, জেভিএম মারা যাবে না। তবে অ্যাপ্লিকেশনটি থ্রেডগুলি সূচিত্রে সূত্রগুলির বিজ্ঞপ্তির অপেক্ষায় আটকে রয়েছে যা কোনও ওওম ধরার কারণে পুনরায় শুরু হয়েছিল working
স্টিফেন সি

14

হ্যাঁ, বাস্তব-বিশ্ব পরিস্থিতিতে আছে scen এখানে আমার: নোডের প্রতি সীমাবদ্ধ মেমরির সাথে আমার একটি ক্লাস্টারে অনেকগুলি আইটেমের ডেটা সেটগুলি প্রক্রিয়া করা দরকার। প্রদত্ত জেভিএম উদাহরণ একের পর এক অনেকগুলি আইটেমের মধ্য দিয়ে যায় তবে কিছু আইটেমগুলি ক্লাস্টারে প্রক্রিয়া করার জন্য খুব বড়: আমি কী ধরতে পারি OutOfMemoryErrorএবং কোন আইটেমগুলি খুব বড় তা নোট নিতে পারি। পরে, আমি আরও র‍্যাম সহ কম্পিউটারে কেবলমাত্র বড় আইটেমগুলি আবার চালাতে পারি।

(যেহেতু এটি কোনও একক বহু-গিগাবাইটের বরাদ্দ দেয় যা ব্যর্থ হয়, ত্রুটিটি ধরা পরে জেভিএম এখনও ঠিক আছে এবং অন্যান্য আইটেমগুলি প্রক্রিয়া করার জন্য যথেষ্ট স্মৃতি রয়েছে))


সুতরাং আপনার মত কোড আছে byte[] bytes = new byte[length]? কেন শুধু sizeআগের পয়েন্টে চেক করবেন না ?
রায়েদওয়াল্ড

4
কারণ sizeআরও স্মৃতির সাথে একই হবে fine আমি ব্যতিক্রমটি দিয়ে যাচ্ছি কারণ বেশিরভাগ ক্ষেত্রে সবকিছু ঠিক থাকবে।
মাইকেল কুহন

10

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

উপরের আইডিইএর দৃশ্যের পাশাপাশি, সাধারণভাবে ধরা কেবল থ্রোব্যাবলের হওয়া উচিত, কেবল ওএম নির্দিষ্টভাবে নয়, এবং এমন একটি প্রসঙ্গে করা উচিত যেখানে কমপক্ষে থ্রেডটি শীঘ্রই বন্ধ হয়ে যাবে।

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


8

আমি এই প্রশ্নটি পেরিয়ে এসেছি কারণ আমি ভাবছিলাম যে আমার ক্ষেত্রে আউটআফমিউরিওর ধরা খুব ভাল ধারণা কিনা। আমি এখানে আংশিকভাবে উত্তর দিচ্ছি অন্য একটি উদাহরণ দেখানোর জন্য যখন এই ত্রুটিটি ধরা পড়ে তখন কারও কাছে বোঝা যায় (ie আমি) এবং আংশিকভাবে এটি আমার ক্ষেত্রে সত্য ধারণা কিনা তা সম্পর্কে জানতে (আমার সাথে একটি উবার জুনিয়র বিকাশকারী হিসাবে আমি কখনই পারি না) আমি যে কোনও কোডের কোড লিখেছি সে সম্পর্কে খুব নিশ্চিত হন)।

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

BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); 
bitmapOptions.inSampleSize = 1;
boolean imageSet = false;
while (!imageSet) {
  try {
    image = BitmapFactory.decodeFile(filePath, bitmapOptions);
    imageView.setImageBitmap(image); 
    imageSet = true;
  }
  catch (OutOfMemoryError e) {
    bitmapOptions.inSampleSize *= 2;
  }
}

এইভাবে আমি তাদের, বা বরং তাদের ব্যবহারকারীর চাহিদা এবং প্রত্যাশা অনুযায়ী কম বেশি শক্তিশালী ডিভাইস সরবরাহ করতে পরিচালিত করি।


4
আরেকটি বিকল্প হ'ল চেষ্টা করা এবং ব্যর্থ হওয়ার পরিবর্তে আপনি কত বড় বিটম্যাপ হ্যান্ডেল করতে পারবেন তা গণনা করা হবে। "ব্যতিক্রম ব্যতিক্রমী মামলাগুলির জন্য ব্যবহার করা উচিত" - আমি মনে করি কেউ বলেছিলেন। তবে আমি বলব, আপনার সমাধানটি সবচেয়ে সহজ উপায় বলে মনে হচ্ছে, সম্ভবত সেরা নয়, তবে সম্ভবত সবচেয়ে সহজ।
jontejj

এটি কোডেকের উপর নির্ভর করে। 10 এমবি এর একটি বিএমপি কল্পনা করুন সম্ভবত 10MB হিপ থেকে সামান্য কিছু বেশি হবে, যখন 10MB এর একটি JPEG "বিস্ফোরিত হবে"। আমার ক্ষেত্রে একইভাবে যেখানে আমি একটি এক্সএমএল বিশ্লেষণ করতে চাই যা সামগ্রীর জটিলতার উপর নির্ভর করে ব্যাপকভাবে পরিবর্তিত হতে পারে
ড্যানিয়েল অ্যাল্ডার

5

হ্যাঁ, আসল প্রশ্নটি "আপনি ব্যতিক্রম হ্যান্ডলারটিতে কী করতে যাচ্ছেন?" প্রায় দরকারী যে কোনও কিছুর জন্য, আপনি আরও মেমরি বরাদ্দ করবেন। যদি আপনি কোনও ডায়াগনস্টিক কাজ করতে চান যখন কোনও আউটআফমিরিরিয়ার ঘটে, আপনি -XX:OnOutOfMemoryError=<cmd>হটস্পট ভিএম দ্বারা সরবরাহিত হুক ব্যবহার করতে পারেন । যখন কোনও আউটআফমিরিরিয়ার ঘটে তখন এটি আপনার কমান্ড (গুলি) কার্যকর করবে এবং আপনি জাভার স্তূপের বাইরে কার্যকর কিছু করতে পারেন। আপনি অ্যাপ্লিকেশনটিকে প্রথম স্থানে মেমরির বাইরে চলে যেতে চান, সুতরাং কেন এটি ঘটে তা নির্ধারণ করা প্রথম পদক্ষেপ। তারপরে আপনি উপযুক্ত হিসাবে ম্যাক্সপার্মসাইজের হিপ আকার বাড়াতে পারেন। এখানে আরও কিছু দরকারী হটস্পট হুক রয়েছে:

-XX:+PrintCommandLineFlags
-XX:+PrintConcurrentLocks
-XX:+PrintClassHistogram

সম্পূর্ণ তালিকা এখানে দেখুন


এটি আপনার ভাবনার চেয়েও খারাপ। কারণ OutOfMemeoryError আপনার প্রোগ্রামের যে কোনও বিন্দুতে একটি নিক্ষেপ করা যেতে পারে (কেবলমাত্র কোনও newবিবৃতি থেকে নয় ) আপনি যখন এক্সটেকশনটি ধরবেন তখন আপনার প্রোগ্রামটি অপরিজ্ঞাত অবস্থায় থাকবে।
রায়েডওয়াল্ড

5

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

বুলিয়ান isOutOfMemory = মিথ্যা; // প্রতিবেদনের জন্য ব্যবহৃত পতাকা
চেষ্টা করুন
   সোমারটাইপ লার্জার;
   // প্রধান লুপ যা লার্জভারকে আরও বেশি পরিমাণে বরাদ্দ দেয়
   // ঠিক আছে, বা আউটমোমরিরির উত্থাপন করতে পারে
}
ধরা (আউট অফ মেমরিরির প্রাক্তন) {
   // largeVar এখন সুযোগের বাইরে, তাই আবর্জনা
   System.gc (); // বৃহত্তর ডেটা পরিষ্কার করুন
   isOutOfMemory = সত্য; // পতাকা ব্যবহারের জন্য উপলব্ধ
}
// প্রোগ্রাম পুনরুদ্ধারের রিপোর্ট করতে পতাকা পরীক্ষা করে

এটি প্রতিবার একক থ্রেডযুক্ত অ্যাপ্লিকেশনগুলিতে কাজ করে। তবে আমি সম্প্রতি আমার পরীক্ষার ইঞ্জিনটি ইউআই থেকে পৃথক কর্মী-থ্রেডে রেখেছি। এখন, স্মৃতি ছাড়িয়ে যাওয়া উভয় থ্রেডে নির্বিচারে ঘটতে পারে এবং এটি কীভাবে ধরতে হবে তা আমার কাছে পরিষ্কার নয়।

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


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

4

ওম ক্যাচ করা যেতে পারে তবে সাধারণভাবে অকেজো হতে চলেছে, যদি জেভিএম ক্যাচটি পৌঁছে যায় তখন কিছু জিনিস সংগ্রহ করতে সক্ষম হয় এবং সেই সময়ের মধ্যে কত হিপ মেমরি ছেড়ে যায় তার উপর নির্ভর করে।

উদাহরণ: আমার জেভিএম-এ, এই প্রোগ্রামটি সমাপ্তির দিকে চলে:

import java.util.LinkedList;
import java.util.List;

public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();

        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
        }
        System.out.println("Test finished");
    }  
}

তবে, ক্যাচটিতে কেবল একটি লাইন যুক্ত করা আপনাকে দেখাবে যে আমি কী সম্পর্কে বলছি:

import java.util.LinkedList;
import java.util.List;

public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();

        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
            System.out.println("size:" +ll.size());
        }
        System.out.println("Test finished");
    }
}

প্রথম প্রোগ্রামটি ঠিকঠাক হয়ে যায় কারণ যখন ক্যাচটি পৌঁছে যায়, জেভিএম সনাক্ত করে যে তালিকাটি আর ব্যবহার করা হচ্ছে না (এই সনাক্তকরণটি সংকলনের সময় করা একটি অপ্টিমাইজেশনও হতে পারে)। সুতরাং আমরা যখন মুদ্রণ বিবৃতিতে পৌঁছেছি তখন হিপ মেমরিটি প্রায় পুরোপুরি মুক্ত হয়ে গেছে, সুতরাং চালিয়ে যাওয়ার জন্য এখন আমাদের চালকের বিস্তৃত মার্জিন রয়েছে। এটি সেরা কেস।

যাইহোক, কোডটি যদি সাজানো থাকে যেমন llOOM ক্যাচ করার পরে তালিকাটি ব্যবহার করা হয়, JVM এটি সংগ্রহ করতে অক্ষম। এটি দ্বিতীয় স্নিপেটে ঘটে। একটি নতুন লং ক্রিয়েশনের মাধ্যমে ট্রিগার হওয়া ওওমে ধরা পড়েছে, তবে শীঘ্রই আমরা একটি নতুন অবজেক্ট ( System.out,printlnলাইনে একটি স্ট্রিং ) তৈরি করছি , এবং গাদাটি প্রায় পূর্ণ হয়ে গেছে, সুতরাং একটি নতুন ওওম নিক্ষেপ করা হবে। এটি সবচেয়ে খারাপ পরিস্থিতি: আমরা একটি নতুন অবজেক্ট তৈরি করার চেষ্টা করেছি, আমরা ব্যর্থ হয়েছি, আমরা ওওকে ধরেছি, হ্যাঁ, তবে এখন নতুন হিপ মেমরির প্রয়োজন প্রথম নির্দেশনা (যেমন: একটি নতুন অবজেক্ট তৈরি করা) একটি নতুন ওমকে ফেলে দেবে। এটি ভেবে দেখুন, এত অল্প স্মৃতি রেখে আমরা এই মুহুর্তে আর কী করতে পারি ?. সম্ভবত সরে যাচ্ছেন। তাই অকেজো।

জেভিএম সংস্থান সংগ্রহ না করার কারণগুলির মধ্যে একটি সত্যই ভীতিজনক: অন্যান্য থ্রেডের সাথে একটি ভাগ করা সংস্থানও এটি ব্যবহার করে। মস্তিষ্ক সহ যে কেউ যে কোনও ধরণের অ-পরীক্ষামূলক অ্যাপে sertedোকানো থাকলে ওওমকে ধরা কতটা বিপজ্জনক হতে পারে তা দেখতে পাবে।

আমি একটি উইন্ডোজ এক্স 86 32 বিবিটি জেভিএম (জেআর 6) ব্যবহার করছি। প্রতিটি জাভা অ্যাপ্লিকেশনের জন্য ডিফল্ট মেমরি 64MB।


আমি যদি ll=nullব্লকটির ভিতরে যা করি ?
নানভান্নল্লা

3

আমি OOM ত্রুটিগুলি কেন ধরা পড়ার একমাত্র কারণ হ'ল এটি হতে পারে যে আপনি কিছু বিশাল ডেটা স্ট্রাকচার ব্যবহার করছেন যা আপনি আর ব্যবহার করছেন না এবং কিছুটা মেমোরি বাতিল করে দিতে পারে। তবে (১) এর অর্থ হল আপনি মেমোরি নষ্ট করছেন, এবং আপনার কোডটি কোনও ওওমের পরে কেবল দুর্বল হওয়ার পরিবর্তে আপনার ঠিক করা উচিত এবং (২) আপনি এটি ধরলেও, আপনি কী করবেন? OOM যে কোনও সময় ঘটতে পারে, সম্ভাব্যভাবে সমস্ত কিছু অর্ধেক করে রেখে।


3

2 প্রশ্নের জন্য আমি ইতিমধ্যে বালুসকীর দ্বারা প্রস্তাবিত সমাধানটি দেখতে পাচ্ছি।

  1. Java.lang.OutOfMemoryError ধরার সময় কী কোনও বাস্তব শব্দের দৃশ্য আছে?

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


3

আমার কেবলমাত্র এমন দৃশ্য আছে যেখানে কোনও আউটআফমিউরিওর ধরাটি বোধগম্য মনে হয় এবং কাজ করে বলে মনে হয়।

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

সাবলীল জুমিংয়ের কারণে, আমি স্মৃতিতে বিটম্যাপগুলি রাখতে চাই। তবে, অ্যান্ড্রয়েডের স্মৃতিতে সীমাবদ্ধতা রয়েছে যা ডিভাইস নির্ভর এবং যা নিয়ন্ত্রণ করা শক্ত।

এই পরিস্থিতিতে বিটম্যাপটি পড়ার সময় আউটআফমিউরিওর হতে পারে। এখানে, আমি এটি ধরতে এবং তারপরে নিম্ন রেজোলিউশন সহ চালিয়ে যেতে সহায়তা করে।


0
  1. আপনি কীভাবে "ভাল" সংজ্ঞা দেন তার উপর নির্ভর করে। আমরা আমাদের বগি ওয়েব অ্যাপ্লিকেশনটিতে এটি করি এবং এটি বেশিরভাগ সময় কাজ করে (ধন্যবাদ, OutOfMemoryকোনও সম্পর্কযুক্ত স্থিরতার কারণে এখন এটি হয় না)। তবে, আপনি এটি ধরলেও, এটি এখনও কিছু গুরুত্বপূর্ণ কোডটি ভেঙে দিতে পারে: আপনার কয়েকটি থ্রেড থাকলে মেমরির বরাদ্দ এগুলির কোনওটিতেই ব্যর্থ হতে পারে। সুতরাং, আপনার প্রয়োগের উপর নির্ভর করে এর অপরিবর্তনীয়ভাবে ভেঙে যাওয়ার 10-10% সম্ভাবনা রয়েছে।
  2. আমি যতদূর বুঝতে পেরেছি, ভারী স্ট্যাক আনওয়ানডিংয়ের ফলে অনেকগুলি রেফারেন্স অকার্যকর হয়ে যাবে এবং এইভাবে আপনাকে এতো যত্ন নিতে হবে না এমন এত বেশি মেমরি ফ্রি করবে।

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


-1

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

আপনি যদি আউট অফ মেমরিরির ধরতে থাকেন তবে পৃথিবীতে আপনি কী করবেন? ভিএম মেমরির বাইরে নেই, মূলত আপনি যা করতে পারেন তা হল প্রস্থান। আপনি সম্ভবত একটি ডায়ালগ বাক্স খুলতে পারবেন না তাদের বলার জন্য যে আপনি স্মৃতি থেকে দূরে রয়েছেন যেহেতু স্মৃতিটি গ্রহণ করবে :-)

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

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


7
আপনার পোস্টটি স্থায়ী করে দেয় এমন একটি ভুল ধারণাটি OOM ইঙ্গিত করে যে JVM এর স্মৃতিশক্তি নেই। পরিবর্তে, এটি প্রকৃতপক্ষে ইঙ্গিত দেয় যে জেভিএম নির্দেশিত সমস্ত মেমরি বরাদ্দ করতে পারে না। এটি হ'ল, যদি জেভিএমের 10B স্পেস থাকে এবং আপনি 100B অবজেক্টটি 'নতুন আপ' করেন তবে এটি ব্যর্থ হবে, তবে আপনি ঘুরে ফিরে 5B অবজেক্টটি 'নতুন আপ' করতে পারেন এবং ভাল হতে পারেন।
টিম বেন্ডার

4
এবং যদি আমার কেবল 5 বি দরকার হয় তবে আমি কেন 10 বি চাইছি? আপনি যদি পরীক্ষার এবং ত্রুটির ভিত্তিতে বরাদ্দ করে থাকেন তবে আপনি এটি ভুল করছেন।
তোফুবিয়ার

4
আমার ধারণা টিমের অর্থ এই ছিল যে আপনি এখনও আউটআউফ-মেমরির পরিস্থিতি নিয়ে কিছু কাজ করতে পারেন। উদাহরণস্বরূপ, একটি ডায়ালগ খোলার জন্য পর্যাপ্ত মেমরি থাকতে পারে।
স্টিফেন এলার্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.