জাভা স্ট্যাকের আকার বাড়ানো কীভাবে?


123

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

মূলত আমি জেভিএম স্ট্যাকের আকার বাড়াতে চেয়েছিলাম যাতে প্রোগ্রামগুলি বিনা রানের মতো হয় StackOverflowError

public class TT {
  public static long fact(int n) {
    return n < 2 ? 1 : n * fact(n - 1);
  }
  public static void main(String[] args) {
    System.out.println(fact(1 << 15));
  }
}

সংশ্লিষ্ট কনফিগারেশন সেটিংসটি হ'ল java -Xss...একটি বিশাল পরিমাণের মান সহ কমান্ড-লাইন পতাকা। TTউপরের প্রোগ্রামটির জন্য , এটি ওপেনজেডিকের জেভিএম এর সাথে এটির মতো কাজ করে:

$ javac TT.java
$ java -Xss4m TT

উত্তরের একটিতে এটিও চিহ্নিত করা হয়েছে যে -X...পতাকাগুলি বাস্তবায়ন নির্ভর। আমি ব্যবহার করছিলাম

java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8.1) (6b18-1.8.1-0ubuntu1~8.04.3)
OpenJDK 64-Bit Server VM (build 16.0-b13, mixed mode)

কেবল একটি থ্রেডের জন্য একটি বৃহত স্ট্যাক নির্দিষ্ট করাও সম্ভব (কীভাবে উত্তরের একটিতে দেখুন)। এটি সুপারিশ করা হয়java -Xss... থ্রেড এটি প্রয়োজন হবে না জন্য এড়ানোর নাশক মেমরি।

আমি কৌতূহলী ছিলাম যে প্রোগ্রামটি কতটা বড় প্রয়োজন ঠিক তার উপরে প্রয়োজনীয়, তাই আমি এটি nচালিয়েছি:

  • -Xss4m এর জন্য যথেষ্ট হতে পারে fact(1 << 15)
  • -Xss5m এর জন্য যথেষ্ট হতে পারে fact(1 << 17)
  • -Xss7m এর জন্য যথেষ্ট হতে পারে fact(1 << 18)
  • -Xss9m এর জন্য যথেষ্ট হতে পারে fact(1 << 19)
  • -Xss18m এর জন্য যথেষ্ট হতে পারে fact(1 << 20)
  • -Xss35m এর জন্য যথেষ্ট হতে পারে fact(1 << 21)
  • -Xss68m এর জন্য যথেষ্ট হতে পারে fact(1 << 22)
  • -Xss129m এর জন্য যথেষ্ট হতে পারে fact(1 << 23)
  • -Xss258m এর জন্য যথেষ্ট হতে পারে fact(1 << 24)
  • -Xss515m এর জন্য যথেষ্ট হতে পারে fact(1 << 25)

উপরের সংখ্যাগুলি থেকে দেখে মনে হচ্ছে যে জাভা উপরের ফাংশনটির জন্য স্ট্যাক ফ্রেমে প্রায় 16 বাইট ব্যবহার করছে যা যুক্তিযুক্ত।

শুমার উপরে রয়েছে যথেষ্ট হতে পারে পরিবর্তে যথেষ্ট , কারণ স্ট্যাক প্রয়োজন সেটি নিয়ামক নয়: এটা একই উৎস ফাইলের সাথে একাধিক বার চলমান এবং একই -Xss...কখনও কখনও সফল এবং কখনও কখনও একটি উৎপাদ StackOverflowError। উদাহরণস্বরূপ 1 << 20 এর জন্য, -Xss18m10 টির মধ্যে 7 রানের মধ্যে যথেষ্ট ছিল এবং -Xss19mসর্বদা যথেষ্ট ছিল না, তবে -Xss20mযথেষ্ট ছিল (100 এর মধ্যে 100 রানের মধ্যে)। আবর্জনা সংগ্রহ, জেআইটি লাথি মারছে, বা অন্য কোনও কিছুর কারণে এই অমানবিক আচরণের কারণ হয়?

একটিতে মুদ্রিত স্ট্যাক ট্রেস StackOverflowError(এবং সম্ভবত অন্যান্য ব্যতিক্রমগুলিতেও) রানটাইম স্ট্যাকের সাম্প্রতিক 1024 টি উপাদান দেখায়। নীচে একটি উত্তর দেখায় যে কীভাবে সঠিক গভীরতা পৌঁছেছে তা গণনা করতে হবে (যা 1024 এর চেয়ে অনেক বেশি বড় হতে পারে)।

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

public class TTIterative {
  public static long fact(int n) {
    if (n < 2) return 1;
    if (n > 65) return 0;  // Enough powers of 2 in the product to make it (long)0.
    long f = 2;
    for (int i = 3; i <= n; ++i) {
      f *= i;
    }
    return f;
  }
  public static void main(String[] args) {
    System.out.println(fact(1 << 15));
  }
}

এফওয়াইআই, উপরের পুনরাবৃত্ত সমাধানটি দেখায় যে, factফাংশনটি 65 (উপরে, এমনকি 20 এরও বেশি) উপরে সংখ্যার সঠিক ফ্যাক্টরিয়ালটি গণনা করতে পারে না, কারণ জাভা অন্তর্নির্মিত প্রকারটি longউপচে পড়বে। রিফ্যাক্টরিং factযাতে এটি BigIntegerপরিবর্তে পরিবর্তিত হয় longতবে বড় ইনপুটগুলির জন্যও সঠিক ফলাফল পাওয়া যায়।


দেখতে এটি দেখতে আরও সহজ দেখাচ্ছে। ফ্যাক্ট () কে 32K বার পুনরাবৃত্তভাবে বলা হয়। এটি স্ট্যাকের 1MB এর চেয়ে কম হওয়া উচিত। : - /
হারুন ডিগুল্লা

অ্যারন: + ফাংশন ওভারহেড, যা এটি ..
অনেকটা

4
আপনার স্ট্যাকের সমস্যাগুলি বাদ দিন। মনে রাখবেন যে আপনি আপনার দীর্ঘ এবং ints উড়িয়ে দিচ্ছেন। 1 << 4 সর্বোচ্চ মান আমি BigInteger ব্যবহার মধ্যে 0. চেষ্টা নেতিবাচক এবং তারপর যাবার আগে ব্যবহার করতে পারেন
শন

নিশ্চিত না যে ফাংশন ওভারহেডটি বাস্তবে অনেকটা থাআট আছে - আমি মনে করি আপনার এখনও কিছু মেগাবাইট স্ট্যাকের জায়গার ক্রমে 2 ^ 15 কল করতে সক্ষম হওয়া উচিত।
নিল কফফি

7
দ্রষ্টব্য: আপনি প্রতিটি থ্রেডের স্ট্যাক আকার নির্ধারণ করছেন এবং একটি অর্থের কোডের রেখাটিকে এড়াতে সমস্ত অর্থহীন ফলাফল তৈরি করছেন। আপনি আপনার অগ্রাধিকার অনুসারে বাছাই করায় আমি আনন্দিত। : পি
পিটার লরে

উত্তর:


78

হুম ... এটি আমার পক্ষে এবং 999MB স্ট্যাকের চেয়ে কম সহকারে কাজ করে:

> java -Xss4m Test
0

(উইন্ডোজ জেডিকে,, ১.0.০-বি05 ক্লায়েন্ট ভিএম, এবং লিনাক্স জেডিকে posted - আপনার পোস্টের মতো একই সংস্করণ তথ্য তৈরি করুন)


1
সম্ভবত এটি আমার মন্তব্যের জন্য ছিল, আমি যখন নীল পোস্ট করেছিলেন ঠিক একই জিনিসটি বুঝতে পেরে আমি এটি মুছে ফেলেছিলাম।
শান

এই প্রশ্ন এবং আপনার উত্তরের জন্য ধন্যবাদ, আমি আমার দায়িত্ব সম্পূর্ণ করতে পেরেছি। আমার ডিএফএস ফাংশনটির গ্রাফটিতে ~ 10 ^ 5 শীর্ষবিন্দু পুনরাবৃত্তি করতে হয়েছিল। অবশেষে এটি -Xss129 মি: ডি
ভোলাগব্বর

11

আমি ধরে নিয়েছি আপনি স্ট্যাক ট্রেসের পুনরাবৃত্ত রেখাগুলি দ্বারা "1024 এর গভীরতা" গণনা করেছেন?

স্পষ্টতই, থ্রোয়েবেলে স্ট্যাক ট্রেস অ্যারের দৈর্ঘ্য 1024 এর মধ্যে সীমাবদ্ধ বলে মনে হচ্ছে following নীচের প্রোগ্রামটি চেষ্টা করুন:

public class Test {

    public static void main(String[] args) {

        try {
            System.out.println(fact(1 << 15));
        }
        catch (StackOverflowError e) {
            System.err.println("true recursion level was " + level);
            System.err.println("reported recursion level was " +
                               e.getStackTrace().length);
        }
    }

    private static int level = 0;
    public static long fact(int n) {
        level++;
        return n < 2 ? n : n * fact(n - 1);
    }
}

9

আপনি যদি থ্রেড স্ট্যাকের আকারের সাথে খেলতে চান তবে আপনি হটস্পট জেভিএম-এ-এক্সএস বিকল্পটি দেখতে চাইবেন। নন হটস্পট ভিএম এর ক্ষেত্রে এটি আলাদা কিছু হতে পারে যেহেতু জেভিএম-এক্স প্যারামিটারগুলি বিতরণ নির্দিষ্ট, আইআইআরসি are

হটস্পটে, দেখে মনে হচ্ছে এটি java -Xss16Mযদি আপনি 16 মেগা আকার বানাতে চান।

আদর্শ java -X -helpআপনি যে সমস্ত বিতরণ নির্দিষ্ট JVM প্যারামিটারগুলিতে পাস করতে পারেন তা দেখতে চাইলে করুন। এটি অন্যান্য জেভিএমগুলিতে একই কাজ করে কিনা তা আমি নিশ্চিত নই, তবে এটি হটস্পট নির্দিষ্ট পরামিতিগুলির সমস্ত মুদ্রণ করে।

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


8

প্রক্রিয়াটির মধ্যে স্ট্যাকের আকার নিয়ন্ত্রণের একমাত্র উপায় হ'ল নতুন শুরু করা Thread। তবে আপনি -Xssপ্যারামিটার দিয়ে একটি স্ব-কলিং সাব জাভা প্রক্রিয়া তৈরি করেও নিয়ন্ত্রণ করতে পারেন ।

public class TT {
    private static int level = 0;

    public static long fact(int n) {
        level++;
        return n < 2 ? n : n * fact(n - 1);
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(null, null, "TT", 1000000) {
            @Override
            public void run() {
                try {
                    level = 0;
                    System.out.println(fact(1 << 15));
                } catch (StackOverflowError e) {
                    System.err.println("true recursion level was " + level);
                    System.err.println("reported recursion level was "
                            + e.getStackTrace().length);
                }
            }

        };
        t.start();
        t.join();
        try {
            level = 0;
            System.out.println(fact(1 << 15));
        } catch (StackOverflowError e) {
            System.err.println("true recursion level was " + level);
            System.err.println("reported recursion level was "
                    + e.getStackTrace().length);
        }
    }

}

এই তথ্যবহুল উত্তরের জন্য ধন্যবাদ, এ ছাড়াও বিকল্পগুলি সম্পর্কে জেনে ভাল লাগছে java -Xss...
pts

1
আমি এটি সম্পর্কে উত্তেজিত হয়ে উঠলাম, কিন্তু তারপরে ডকস.ওরকল / জাভ্যাস / 6 / ডকস / এপি / জাভা / ল্যাং / থ্রেড এইচটিএমএল পড়ার মাধ্যমে - স্ট্যাকসাইজ কনস্ট্রাক্টর - উত্তেজনা চলে গেল।
কেলোগগুলি

আমি অবাক হই যে কোন প্ল্যাটফর্মগুলি সেগুলি যখন ডকুমেন্ট কেবলমাত্র বলে - "কিছু প্ল্যাটফর্মগুলিতে"
ডেনিস সি

3

এই বিকল্পটি যুক্ত করুন

--driver-java-options -Xss512m

আপনার স্পার্ক-জমা দেওয়ার আদেশটি এই সমস্যার সমাধান করবে।


2

আপনি সমস্ত বোধগম্য দৃষ্টিভঙ্গি এড়াতে আগ্রহী হওয়ায় একটি বুদ্ধিমান সমাধান দেওয়া শক্ত। কোডের এক লাইনের রিফ্যাকচারিং হ'ল বুদ্ধিমান সমাধান।

দ্রষ্টব্য: -এসএসএস ব্যবহার করে প্রতিটি থ্রেডের স্ট্যাকের আকার নির্ধারণ করা হয় এবং এটি খুব খারাপ ধারণা।

অন্য একটি পদ্ধতি হ'ল বাইট কোড ম্যানিপুলেশন কোডটি নিম্নরূপে পরিবর্তন করতে;

public static long fact(int n) { 
    return n < 2 ? n : n > 127 ? 0 : n * fact(n - 1); 
}

এন> 127 এর জন্য প্রতিটি উত্তর দেওয়া হয় 0 হয় এটি উত্স কোড পরিবর্তন করা এড়ায়।


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

1
@ পিটিএস, আপনার ধন্যবাদ উল্লেখ করা হয় আমি মনে করি এটি অনেক বেশি জটিল ব্যবহারের ক্ষেত্রে দেওয়া একটি বুদ্ধিমান প্রশ্ন, তবে সেগুলি খুব বিরল।
পিটার লরি

0

অদ্ভুত! আপনি বলছেন যে আপনি 1 << 15 গভীরতার পুনরাবৃত্তি তৈরি করতে চান ??? !!!!

আমি এটি চেষ্টা না করার পরামর্শ দিই। স্ট্যাকের আকার হবে 2^15 * sizeof(stack-frame)। স্ট্যাক-ফ্রেমের আকার কী তা আমি জানি না, তবে 2 ^ 15 323268। খুব অনেক ... ঠিক আছে, যদি এটি 1024 (2 ^ 10) এ থামে তবে আপনাকে এটিকে 2 actual 5 গুণ বড় করতে হবে, এটি আপনার আসল সেটিংসের চেয়ে 32 গুণ বড়।


0

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

এই পোস্টে একটি গ্যাণ্ডার নিন, এতে ফাংশন এবং কোড সম্পর্কে কিছু বিশ্লেষণ রয়েছে:

http://threebrothers.org/brendan/blog/stirlings-approximation-formula-clojure/


0

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

  def measureStackDepth(ss: Long): Long = {
    var depth: Long = 0
      val thread: Thread = new Thread(null, new Runnable() {
        override def run() {
          try {
          def sum(n: Long): Long = {depth += 1; if (n== 0) 0 else sum(n-1) + 1}
          println("fact = " + sum(ss * 10))
          } catch {
            case e: StackOverflowError => // eat the exception, that is expected
          }
        }
      }, "deep stack for money exchange", ss)
      thread.start()
      thread.join()
    depth
  }                                               //> measureStackDepth: (ss: Long)Long


  for (ss <- (0 to 10)) println("ss = 10^" +  ss + " allows stack of size " -> measureStackDepth((scala.math.pow (10, ss)).toLong) )
                                                  //> fact = 10
                                                  //| (ss = 10^0 allows stack of size ,11)
                                                  //| fact = 100
                                                  //| (ss = 10^1 allows stack of size ,101)
                                                  //| fact = 1000
                                                  //| (ss = 10^2 allows stack of size ,1001)
                                                  //| fact = 10000
                                                  //| (ss = 10^3 allows stack of size ,10001)
                                                  //| (ss = 10^4 allows stack of size ,1336)
                                                  //| (ss = 10^5 allows stack of size ,5456)
                                                  //| (ss = 10^6 allows stack of size ,62736)
                                                  //| (ss = 10^7 allows stack of size ,623876)
                                                  //| (ss = 10^8 allows stack of size ,6247732)
                                                  //| (ss = 10^9 allows stack of size ,62498160)

আপনি দেখতে পান যে স্ট্যাকটি থ্রেডে বরাদ্দকৃত আরও স্ট্যাকের সাথে তাত্পর্যপূর্ণভাবে গভীরতর হতে পারে।

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