কেন এই পদ্ধতিটি 4 মুদ্রণ করে?


111

আমি ভাবছিলাম যে আপনি যখন স্ট্যাকওভারফ্লো এরর ধরার চেষ্টা করবেন এবং নিম্নলিখিত পদ্ধতিটি নিয়ে এসেছেন তখন কী হবে:

class RandomNumberGenerator {

    static int cnt = 0;

    public static void main(String[] args) {
        try {
            main(args);
        } catch (StackOverflowError ignore) {
            System.out.println(cnt++);
        }
    }
}

এখন আমার প্রশ্ন:

কেন এই পদ্ধতিটি '4' মুদ্রণ করে?

আমি ভেবেছিলাম সম্ভবত এটি System.out.println()কল স্ট্যাকের 3 টি বিভাগের প্রয়োজন, তবে 3 নম্বরটি কোথা থেকে এসেছে তা আমি জানি না। আপনি যখন এর সোর্স কোডটি (এবং বাইকোড) দেখুন System.out.println(), এটি সাধারণত 3 এর চেয়ে অনেক বেশি পদ্ধতিতে আহ্বান জানায় (সুতরাং কল স্ট্যাকের 3 টি অংশই পর্যাপ্ত হবে না)। এটি যদি হটস্পট ভিএম প্রয়োগ করে (পদ্ধতি ইনলাইনিং) অপ্টিমাইজেশনের কারণে হয় তবে আমি ভাবছি যে ফলাফলটি অন্য ভিএম-এর চেয়ে আলাদা হবে if

সম্পাদনা করুন :

আউটপুটটি অত্যন্ত জেভিএম নির্দিষ্ট বলে মনে হচ্ছে, আমি
জাভা (টিএম) এসই রানটাইম এনভায়রনমেন্ট (বিল্ড 1.6.0_41-বি02)
জাভা হটস্পট (টিএম) 64-বিট সার্ভার ভিএম (বিল্ড 20.14-বি01, মিশ্র মোড) ব্যবহার করে ফলাফল 4 পেয়েছি


আমি কেন এই প্রশ্নটি জাভা স্ট্যাক বোঝার থেকে পৃথক বলে মনে করি তা ব্যাখ্যা :

আমার প্রশ্ন কেন সেখানে সিএনটি> 0 নেই (স্পষ্টতই কারণ কিছু ছাপার আগে System.out.println()স্ট্যাকের আকার প্রয়োজন এবং অন্যটি ছুঁড়ে ফেলে StackOverflowError) তবে কেন এটির যথাক্রমে 4, যথাক্রমে 0,3,8,55 বা অন্য কিছু রয়েছে সিস্টেম।


4
আমার স্থানীয় ক্ষেত্রে, আমি প্রত্যাশা অনুযায়ী "0" পাচ্ছি।
রেড্ডি

2
এটি অনেকগুলি আর্কিটেকচার স্টাফের সাথে ডিল করতে পারে। আপনার জেডকে সংস্করণ সহ আপনার আউটপুটটি আরও ভাল পোস্ট করুন আমার জন্য আউটপুট 0 জেডিকে 1.7 এ 0
লোকেশ

3
আমি পেয়েছি 5, 6এবং 38জাভা দিয়ে 1.7.0_10
কন

8
@ লিস্ট আপনি যখন অন্তর্নিহিত আর্কিটেকচারের সাথে জড়িত কৌশলগুলি করছেন তখন একই আউটপুট হবে না;)
এম0স্কিট ০৪

3
@ ফ্লার্নব এটি বন্ধনীগুলি সীমাবদ্ধ করার জন্য আমি কেবল একটি স্টাইল ব্যবহার করি। শর্তাবলী এবং ফাংশনগুলি কোথায় শুরু হয় এবং শেষ হয় তা আমার পক্ষে জানা সহজ করে তোলে। আপনি চাইলে এটি পরিবর্তন করতে পারেন তবে আমার মতে এটি এইভাবে আরও পঠনযোগ্য।
syb0rg

উত্তর:


41

আমি মনে করি কেন অন্যটি সিএনটি> 0 ব্যাখ্যা করার ক্ষেত্রে একটি ভাল কাজ করেছে তবে কেন সিএনটি = 4 সম্পর্কিত কেন এবং সিএনটি বিভিন্ন সেটিংসের মধ্যে কেন এত ব্যাপকভাবে পরিবর্তিত হয় সে সম্পর্কে পর্যাপ্ত বিবরণ নেই। আমি এখানে শূন্যতা পূরণ করার চেষ্টা করব।

দিন

  • এক্স মোট স্ট্যাক আকার হতে হবে
  • যখন আমরা প্রথমবার প্রথম প্রবেশ করি তখন এম স্ট্যাক স্পেস হয়
  • প্রতিবার যখন আমরা মূল প্রবেশ করি তখন স্ট্যাক স্পেস বৃদ্ধি করুন
  • পি চালানোর জন্য প্রয়োজনীয় স্ট্যাক স্পেস হতে হবে System.out.println

যখন আমরা প্রথম প্রধান হয়ে যাই, তখন বাকি স্থানটি এক্সএম। প্রতিটি পুনরাবৃত্তি কল আর মেমরি গ্রহণ করে। সুতরাং 1 পুনরাবৃত্তির কলের জন্য (মূলের চেয়ে 1 টি বেশি) মেমরির ব্যবহার এম + আর ose মনে করুন যে স্ট্যাকওভারফ্লো এরির সি সফল পুনরাবৃত্তির কলগুলির পরে নিক্ষেপ করা হয়, যা, এম + সি * আর <= এক্স এবং এম + সি * (আর + 1)> এক্স। প্রথম স্ট্যাকওভারফ্লো এররের সময়, এক্স - এম - সি * আর মেমরিটি বাকি আছে।

দৌড়াতে সক্ষম হতে System.out.prinln, আমাদের স্ট্যাকের পি পরিমাণ পরিমাণ অবশিষ্ট থাকতে হবে। যদি এটি ঘটে থাকে যে এক্স - এম - সি * আর> = পি হয়, তবে 0 মুদ্রিত হবে। যদি পি-তে আরও স্থানের প্রয়োজন হয়, তবে আমরা স্ট্যাক থেকে ফ্রেমগুলি সরিয়ে, সিএনটি ++ ব্যয়ে আর মেমরি অর্জন করি।

printlnশেষ পর্যন্ত কখন চালাতে সক্ষম হবে, এক্স - এম - (সি - সিএনটি) * আর> = পি। সুতরাং যদি কোনও নির্দিষ্ট সিস্টেমের জন্য পি বড় হয়, তবে সিএনটি বড় হবে।

এর কয়েকটি উদাহরণ দিয়ে এটিকে দেখুন।

উদাহরণ 1: ধরুন

  • এক্স = 100
  • এম = 1
  • আর = 2
  • পি = 1

তারপরে সি = ফ্লোর ((এক্সএম) / আর) = 49 এবং সিএনটি = সিলিং ((পি - (এক্স - এম - সি * আর)) / আর) = 0

উদাহরণ 2: ধরুন

  • এক্স = 100
  • এম = 1
  • আর = 5
  • পি = 12

তারপরে সি = 19 এবং সিএনটি = 2।

উদাহরণ 3: ধরুন

  • এক্স = 101
  • এম = 1
  • আর = 5
  • পি = 12

তারপরে সি = 20, এবং সিএনটি = 3।

উদাহরণ 4: ধরুন

  • এক্স = 101
  • এম = 2
  • আর = 5
  • পি = 12

তারপরে সি = 19 এবং সিএনটি = 2।

সুতরাং, আমরা দেখতে পাই যে সিস্টেম (এম, আর, এবং পি) এবং স্ট্যাকের আকার (এক্স) উভয়ই সিএনটি প্রভাবিত করে।

পার্শ্ব নোট হিসাবে, কত জায়গা catchশুরু করতে হবে তা বিবেচ্য নয় । যতক্ষণ না পর্যাপ্ত জায়গা না থাকে catch, ততক্ষণে সিএনটি বৃদ্ধি পাবে না, সুতরাং কোনও বাহ্যিক প্রভাব নেই।

সম্পাদনা

আমি যা বলেছিলাম তা ফিরিয়ে নিই catch। এটি একটি ভূমিকা পালন করে। মনে করুন এটি শুরু করতে টি পরিমাণ জায়গার প্রয়োজন। বামন স্থান টি-টির চেয়ে বেশি হলে সিএনটি বৃদ্ধি পেতে শুরু করে এবং বাম স্থানটি printlnটি + পি এর চেয়ে বেশি হলে চলে runs

সম্পাদনা

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

পরীক্ষার সেটআপ: উবুন্টু 12.04 সার্ভার ডিফল্ট জাভা এবং ডিফল্ট-জেডিকে সহ। Xss 70,000 থেকে 1 বাইট ইনক্রিমেন্ট থেকে 460,000 এ শুরু হয়।

ফলাফলগুলি এখানে উপলভ্য: https://www.google.com/fusiontables/DataSource?docid=1xkJhd4s8biLghe6gZbcfUs3vT5MpS_OnscjWDbM আমি অন্য সংস্করণ তৈরি করেছি যেখানে প্রতিটি পুনর্বার ডেটা পয়েন্ট সরানো হয়। অন্য কথায়, কেবলমাত্র পূর্বের থেকে পৃথক পয়েন্টগুলি দেখানো হয়েছে। এটি অস্বাভাবিকতা দেখতে সহজ করে তোলে। https://www.google.com/fusiontables/DataSource?docid=1XG_SRzrrNasepwZoNHqEAKuZlHiAm9vbEdwfsUA


ভাল সংক্ষিপ্তসার জন্য আপনাকে ধন্যবাদ, আমি অনুমান করি যে এগুলি সমস্ত প্রশ্নটি ফুটে উঠেছে: এম, আর এবং পি কী প্রভাব ফেলবে (যেহেতু এক্স ভিএম-বিকল্প-এক্সএসএস দ্বারা সেট করা যেতে পারে)?
flrnb

@flrnb এম, আর, এবং পি সিস্টেম নির্দিষ্ট। এগুলি আপনি সহজেই পরিবর্তন করতে পারবেন না। আমি আশা করি সেগুলিও কিছু প্রকাশের মধ্যে পার্থক্য করবে to
জন সোসেং

তাহলে, কেন আমি এক্সএস (ওরফে এক্স) পরিবর্তন করে বিভিন্ন ফলাফল পাব? এম, আর এবং পি একই থাকে, আপনার সূত্র অনুসারে সিএনটি প্রভাবিত করা উচিত নয়, বা আমি ভুল করছি?
flrnb

এই ভেরিয়েবলগুলির স্বতন্ত্র প্রকৃতির কারণে @flrnb এক্স একাই সিএনটি পরিবর্তন করে। 2 এবং 3 উদাহরণগুলি কেবল এক্সে পৃথক, তবে সিএনটি ভিন্ন।
জন সাশেং

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

20

এটি খারাপ পুনরাবৃত্তির কলটির শিকার। আপনি যখন ভাবছেন যে কেন সিএনটির মান পরিবর্তিত হয়, কারণ স্ট্যাকের আকার প্ল্যাটফর্মের উপর নির্ভর করে। উইন্ডোজে জাভা এসই 6 এর 322-বিট ভিএম-তে 320 কে এবং 24৪-বিট ভিএম-এ 1024 কে মাপের ডিফল্ট স্ট্যাক রয়েছে। আপনি এখানে আরও পড়তে পারেন ।

আপনি বিভিন্ন স্ট্যাক আকার ব্যবহার করে চালাতে পারেন এবং স্ট্যাকের ওভারফ্লো হওয়ার আগে আপনি cnt এর বিভিন্ন মান দেখতে পাবেন-

java -Xss1024k র্যান্ডম নাম্বার জেনারেটর

আপনি সিএনটির মান একাধিক বার মুদ্রিত হতে দেখছেন না যদিও মানটি কখনও কখনও 1 এরও বেশি হয়ে থাকে কারণ আপনার মুদ্রণ বিবরণীতেও ত্রুটি ছুঁড়েছে যা আপনি ডিগ্রো করতে পারবেন Eclipse বা অন্যান্য IDE এর মাধ্যমে নিশ্চিত হয়ে।

আপনি যদি পছন্দ করেন তবে প্রতি বিবৃতি কার্যকর করতে ডিবাগ করতে কোডটি নিম্নলিখিতটিতে পরিবর্তন করতে পারেন-

static int cnt = 0;

public static void main(String[] args) {                  

    try {     

        main(args);   

    } catch (Throwable ignore) {

        cnt++;

        try { 

            System.out.println(cnt);

        } catch (Throwable t) {   

        }        
    }        
}

হালনাগাদ:

এটি যেমন আরও বেশি মনোযোগ পাচ্ছে, আসুন বিষয়গুলিকে আরও স্পষ্ট করে তোলার আরও একটি উদাহরণ দেওয়া যাক-

static int cnt = 0;

public static void overflow(){

    try {     

      overflow();     

    } catch (Throwable t) {

      cnt++;                      

    }

}

public static void main(String[] args) {

    overflow();
    System.out.println(cnt);

}

একটি খারাপ পুনরাবৃত্তি করার জন্য আমরা ওভারফ্লো নামে আরও একটি পদ্ধতি তৈরি করেছি এবং ক্যাচ ব্লক থেকে প্রিন্টলেন স্টেটমেন্টটি সরিয়ে ফেলেছি যাতে এটি মুদ্রণের চেষ্টা করার সময় অন্য একটি ত্রুটি সেটাকে ছুঁড়তে শুরু করে না। এটি প্রত্যাশার মতো কাজ করে। আপনি System.out.println (cnt) লাগানোর চেষ্টা করতে পারেন ; উপরে সিএনটি ++ পরে বিবৃতি এবং সংকলন করুন। তারপরে একাধিকবার চালান। আপনার প্ল্যাটফর্মের উপর নির্ভর করে আপনি সিএনটির বিভিন্ন মান পেতে পারেন ।

এই কারণেই আমরা সাধারণত ত্রুটিগুলি ধরি না কারণ কোডে রহস্য কল্পনা নয়।


13

আচরণটি স্ট্যাকের আকারের উপর নির্ভরশীল (যা ব্যবহার করে ম্যানুয়ালি সেট করা যেতে পারে XssThe স্ট্যাকের আকারটি আর্কিটেকচার নির্দিষ্ট। জেডিকে source উত্স কোড থেকে :

// উইন্ডোজ ডিফল্ট স্ট্যাক আকার নির্বাহী দ্বারা নির্ধারিত হয় (java.exe
// 320K / 1MB [32 বিট / 64 বিট] এর একটি ডিফল্ট মান আছে)। উইন্ডোজ সংস্করণের উপর নির্ভর করে
// থ্রেডস্ট্যাকসাইজকে নন-শূন্যে পরিবর্তন করলে মেমরির ব্যবহারে উল্লেখযোগ্য প্রভাব থাকতে পারে।
// os_windows.cpp এ মন্তব্যগুলি দেখুন।

সুতরাং যখন StackOverflowErrorনিক্ষেপ করা হয় তখন ত্রুটিটি ধরা পড়ে ব্লকটিতে। এখানে println()আবার স্ট্যাক কল যা ব্যতিক্রম আবার ছুঁড়েছে। এটি পুনরাবৃত্তি হয়।

এটি কতবার পুনরাবৃত্তি করে? - আচ্ছা এটি নির্ভর করে যখন জেভিএম মনে করে যে এটি আর স্ট্যাকওভারফ্লো নয়। এবং এটি প্রতিটি ফাংশন কল (খুঁজে পাওয়া কঠিন) এবং এর স্ট্যাক আকারের উপর নির্ভর করে Xss। উপরে উল্লিখিত হিসাবে প্রতিটি ফাংশন কলের মোট আকার এবং আকার (মেমরি পৃষ্ঠার আকারের উপর নির্ভর করে) প্ল্যাটফর্ম নির্দিষ্ট specific অতএব বিভিন্ন আচরণ।

কলিং javaকলের মাধ্যমে -Xss 4Mআমাকে দেয় 41। সুতরাং পরস্পর সম্পর্কিত।


4
স্ট্যাকের আকারটি ফলাফলকে কেন প্রভাব ফেলবে তা আমি পাই না, কারণ আমরা যখন cnt এর মান মুদ্রণের চেষ্টা করি তখন এটি ইতিমধ্যে ছাড়িয়ে যায়। সুতরাং, "প্রতিটি ফাংশন কলের স্ট্যাক আকার" থেকে একমাত্র পার্থক্য আসতে পারে। এবং আমি বুঝতে পারছি না কেন একই জেভিএম সংস্করণ চালিত 2 টি মেশিনের মধ্যে এটি আলাদা হওয়া উচিত।
ফ্লার্নব

সঠিক আচরণটি কেবল জেভিএম উত্স থেকে পাওয়া যেতে পারে। তবে কারণটি এটি হতে পারে। মনে রাখবেন এমনকি catchএকটি ব্লক এবং এটি স্ট্যাকের মধ্যে মেমরি ধারণ করে। প্রতিটি পদ্ধতি কল কত মেমরি নেয় তা জানা যায়নি। স্ট্যাকটি সাফ হয়ে গেলে আপনি আরও একটি ব্লক যুক্ত করছেন catch। এই আচরণ হতে পারে। এটি কেবল জল্পনা।
যতীন

এবং স্ট্যাকের আকার দুটি পৃথক মেশিনে পৃথক হতে পারে। স্ট্যাকের আকার অনেকগুলি ওএস-ভিত্তিক ফ্যাক্টরগুলির উপর নির্ভর করে যথা মেমরি পৃষ্ঠা-আকার ইত্যাদি
যতীন

6

আমি মনে করি প্রদর্শিত নম্বরটি System.out.printlnকলটি Stackoverflowব্যতিক্রম ছোঁড়ার সময় ।

এটি সম্ভবত এটি প্রয়োগ করা printlnএবং স্ট্যাকিং কলটির সংখ্যার প্রয়োগের উপর নির্ভর করে ।

একটি নিদর্শন হিসাবে:

main()কল ট্রিগার Stackoverflowকল আমি ব্যতিক্রম। মূল আই -1 কলটি ব্যতিক্রম ধরা দেয় এবং কল করে printlnযা দ্বিতীয়টি ট্রিগার করে Stackoverflowcntইনক্রিমেন্টটি 1 এ পান। মূল ধরার আই -2 কল এখন ব্যতিক্রম এবং কল println। ইন printlnএকটি পদ্ধতি 3 য় ব্যতিক্রম triggering বলা হয়। cntবৃদ্ধি 2. এই অবিরত পর্যন্ত পেতে printlnতার সকল প্রয়োজনীয় কল করতে পারেন এবং পরিশেষে মান প্রদর্শন cnt

এটি তখন বাস্তব বাস্তবায়নের উপর নির্ভরশীল println

জেডি কে either এর জন্য এটি সাইক্লিং কল সনাক্ত করে এবং ব্যতিক্রমটি আগে ছুঁড়ে দেয় হয় হয় কিছুটা স্ট্যাক রিসোর্স রাখে এবং প্রতিকারের যুক্তির জন্য কিছু জায়গা দেওয়ার সীমাতে পৌঁছানোর আগে ব্যতিক্রম ছুঁড়ে দেয় হয় printlnবাস্তবায়ন কল দেয় না হয় হয় ++ অপারেশন পরে সম্পন্ন হয় printlnকল এইভাবে ব্যতিক্রম পাশ হয়।


"আমি ভেবেছিলাম এটি সম্ভবত কারণ কল স্ট্যাকের জন্য সিস্টেম.আউট.প্রিন্টলনের 3 টি বিভাগের প্রয়োজন ছিল" - এর অর্থ আমি এটাই বোঝাতে চেয়েছি - তবে আমি বিস্মিত হয়েছিলাম কেন এটি ঠিক এই সংখ্যাটি এবং এখন আমি আরও বিস্মিত হয়েছি কেন সংখ্যাটি এত বড়ভাবে আলাদা হয় তার মধ্যে কেন? (ভার্চুয়াল) মেশিনগুলি
flrnb

আমি এর সাথে আংশিকভাবে একমত আছি তবে যা আমি দ্বিমত পোষণ করছি তা হ'ল প্রিন্টলনের প্রকৃত বাস্তবায়নের উপর নির্ভরশীল `
যতীন

6
  1. mainযতক্ষণ না এটি পুনরাবৃত্তির গভীরতায় স্ট্যাকটিকে উপচে ফেলেছে ততক্ষণ নিজেকে পুনরাবৃত্তি করে R
  2. পুনরাবৃত্তির গভীরতায় ক্যাচ ব্লকটি R-1চালানো হয়।
  3. পুনরাবৃত্তির গভীরতায় ক্যাচ ব্লক R-1মূল্যায়ন করে cnt++
  4. গভীরতার R-1কলগুলিতে ক্যাচ ব্লক println, cntস্ট্যাকের পুরানো মান রেখে । printlnঅভ্যন্তরীণভাবে অন্যান্য পদ্ধতিগুলিতে কল করবে এবং স্থানীয় ভেরিয়েবল এবং জিনিসগুলি ব্যবহার করবে। এই সমস্ত প্রক্রিয়াগুলির জন্য স্ট্যাক স্পেস প্রয়োজন।
  5. স্ট্যাকটি ইতিমধ্যে সীমাটি চরিত করছে এবং কলিং / এক্সিকিউটিভের printlnজন্য স্ট্যাকের জায়গার প্রয়োজন হয়, একটি নতুন স্ট্যাক ওভারফ্লো গভীরতার R-1পরিবর্তে গভীরতার দিকে ট্রিগার করা হয় R
  6. পদক্ষেপগুলি 2-5 আবার ঘটে তবে পুনরাবৃত্তির গভীরতায় R-2
  7. পদক্ষেপগুলি 2-5 আবার ঘটে তবে পুনরাবৃত্তির গভীরতায় R-3
  8. পদক্ষেপগুলি 2-5 আবার ঘটে তবে পুনরাবৃত্তির গভীরতায় R-4
  9. পদক্ষেপগুলি আবার ঘটে, তবে পুনরাবৃত্তির গভীরতায় R-5
  10. এটি এমনটি ঘটে যে printlnসম্পূর্ণ করার জন্য এখন পর্যাপ্ত পরিমাণ স্ট্যাক জায়গা রয়েছে (নোট করুন এটি বাস্তবায়নের বিশদ, এটি পৃথক হতে পারে)।
  11. cntগভীরত্বে এ পোস্ট বৃদ্ধি ছিল R-1, R-2, R-3, R-4, এবং পরিশেষে এ R-5। পঞ্চম পোস্ট-ইনক্রিমেন্ট চারটি ফেরত, যা এটি মুদ্রিত হয়েছিল।
  12. mainগভীরতার সাথে সাফল্যের সাথে সমাপ্ত হওয়ার সাথে সাথে R-5, আরও ক্যাপ ব্লকগুলি চালিত না করে পুরো স্ট্যাকটি খুলে যায় এবং প্রোগ্রামটি সম্পূর্ণ হয়।

1

কিছুক্ষণ খোঁড়াখুঁড়ি করার পরে, আমি উত্তরটি খুঁজে পেতে পারি তা বলতে পারি না তবে আমি মনে করি এটি এখন খুব কাছে।

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

যদি এই ধরনের অ্যাক্টিভেশন ফ্রেম তৈরি করার জন্য পর্যাপ্ত মেমরি উপলব্ধ না থাকে তবে একটি স্ট্যাকওভারফ্লো এরির নিক্ষেপ করা হবে।

দ্বিতীয়ত, আমাদের এটিকে পরিষ্কার করা উচিত "" এমন অ্যাক্টিভেশন ফ্রেম তৈরি করার জন্য পর্যাপ্ত মেমরি উপলব্ধ নেই "। জাভা 6 এর জন্য জাভা ভার্চুয়াল মেশিনের স্পেসিফিকেশন অনুসারে ,

ফ্রেমগুলি বরাদ্দ হিপ হতে পারে।

সুতরাং, যখন কোনও ফ্রেম তৈরি করা হয়, তখন স্ট্যাক ফ্রেম তৈরি করার জন্য পর্যাপ্ত হ্যাপ স্পেস এবং নতুন রেফারেন্স সংরক্ষণের জন্য পর্যাপ্ত স্ট্যাক স্পেস থাকতে হবে যা ফ্রেমটি হ্যাপ বরাদ্দ করা থাকলে নতুন স্ট্যাক ফ্রেমের দিকে নির্দেশ করে।

এখন আসুন প্রশ্নে ফিরে আসা যাক। উপরের দিক থেকে, আমরা জানতে পারি যে যখন কোনও পদ্ধতি কার্যকর হয়, তখন এটির জন্য একই পরিমাণে স্ট্যাক স্পেসের দাম পড়তে পারে। এবং System.out.printlnআহ্বানের জন্য (মে) পদ্ধতির অনুরোধের 5 স্তরের প্রয়োজন, সুতরাং 5 টি ফ্রেম তৈরি করা দরকার। তারপরে যখন StackOverflowErrorবাইরে ফেলে দেওয়া হয় তখন 5 ফ্রেমের রেফারেন্সগুলি সঞ্চয় করার জন্য পর্যাপ্ত স্ট্যাক স্থান পেতে 5 বার ফিরে যেতে হয়। সুতরাং 4 প্রিন্ট আউট হয়। কেন 5? কারণ আপনি ব্যবহার cnt++। এটিকে পরিবর্তন করুন ++cntএবং তারপরে আপনি 5 পাবেন।

এবং আপনি লক্ষ্য করবেন যে স্ট্যাকের আকার যখন উচ্চ স্তরে যায়, আপনি মাঝে মাঝে 50 পেয়ে যাবেন। কারণ হ'ল উপলব্ধ গাদা জায়গার পরিমাণটি তখন বিবেচনায় নেওয়া উচিত। স্ট্যাকের আকার যখন খুব বড় হয় তখন স্ট্যাকের আগেই গাদা জায়গাটি ফুরিয়ে যায়। এবং (সম্ভবত) স্ট্যাক ফ্রেমের প্রকৃত আকার System.out.printlnপ্রায় 51 বার main, অতএব এটি 51 বার ফিরে যায় এবং 50 মুদ্রণ করে।


আমার প্রথম চিন্তাটি পদ্ধতি আহ্বানের মাত্রাগুলিও গণনা করা হয়েছিল (এবং আপনি ঠিক বলেছেন, আমি বর্ধিত সিএনটি পোস্ট করেছিলাম সেদিকে আমি মনোযোগ দিইনি), তবে যদি সমাধানটি এত সহজ ছিল তবে ফলাফলগুলি প্ল্যাটফর্মের কেন এত আলাদা হবে? এবং ভিএম বাস্তবায়ন?
flrnb

@flrnb এটি কারণ যে বিভিন্ন প্ল্যাটফর্মগুলি স্ট্যাক ফ্রেমের আকারকে প্রভাবিত করতে পারে এবং জেআরের বিভিন্ন সংস্করণ System.out.printকার্যকর করতে বা পদ্ধতি প্রয়োগের কৌশলকে প্রভাবিত করবে । উপরে বর্ণিত হিসাবে, ভিএম বাস্তবায়ন স্ট্যাক ফ্রেমটি প্রকৃত সঞ্চয় হবে কোথায় তাও প্রভাবিত করে।
জয়

0

এটি প্রশ্নের সঠিক উত্তর নয়, তবে আমি কেবলমাত্র আসল প্রশ্নের মধ্যে কিছু যুক্ত করতে চেয়েছিলাম যা আমি এসেছিলাম এবং আমি কীভাবে সমস্যাটি বুঝলাম:

মূল সমস্যাটিতে ব্যতিক্রম যেখানে ধরা হয়েছিল সেখানে ধরা পড়ে:

উদাহরণস্বরূপ jdk 1.7 এর সাথে এটি উপস্থিতির প্রথম স্থানে ধরা পড়ে।

তবে jdk এর পূর্ববর্তী সংস্করণগুলিতে দেখে মনে হচ্ছে যে ব্যতিক্রমটি ঘটনাক্রমে প্রথম স্থানে ধরা পড়ছে না সুতরাং 4, 50 ইত্যাদি ..

এখন আপনি নিম্নলিখিত হিসাবে চেষ্টা ব্লক অপসারণ

public static void main( String[] args ){
    System.out.println(cnt++);
    main(args);
}

তারপরে আপনি cntপিঁপড়ার সমস্ত মানগুলি নিক্ষিপ্ত ব্যতিক্রমগুলি দেখতে পাবেন (jdk 1.7 এ)।

আমি আউটপুটটি দেখতে নেটবিন ব্যবহার করেছি, কেননা, সেন্টিমিডি সমস্ত আউটপুট এবং ব্যতিক্রম নিক্ষেপ করবে না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.