আমি এই প্রশ্নটি জিজ্ঞাসা করেছিলাম কীভাবে জেভিএম-তে রানটাইম কল স্ট্যাকের আকার বাড়ানো যায়। আমি এর একটি উত্তর পেয়েছি, এবং জাভা কীভাবে একটি বড় রানটাইম স্ট্যাকের প্রয়োজন যেখানে পরিস্থিতি পরিচালনা করে তার সাথে প্রাসঙ্গিক অনেক দরকারী উত্তর এবং মন্তব্য পেয়েছি। আমি প্রতিক্রিয়াগুলির সংক্ষিপ্তসার সহ আমার প্রশ্নটি প্রসারিত করেছি।
মূলত আমি জেভিএম স্ট্যাকের আকার বাড়াতে চেয়েছিলাম যাতে প্রোগ্রামগুলি বিনা রানের মতো হয় 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 এর জন্য, -Xss18m
10 টির মধ্যে 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
তবে বড় ইনপুটগুলির জন্যও সঠিক ফলাফল পাওয়া যায়।