2010-02-18 9 views
9

या तो जावा या सी में मैंयह कोड जावा में स्मृति से क्यों चलाता है, लेकिन सी में नहीं?

fun(){ 
    fun(); 
} 

(अनदेखी वाक्य रचना विवरण) की तरह एक समारोह लिख सकते हैं

जावा में मैं OutOfMemory अपवाद मिलता है लेकिन सी (और शायद कुछ अन्य भाषाओं) में इसे हमेशा के लिए चलाने के लिए लगता है , जैसे कि यह एक अनंत लूप थे। मुझे यहां आउटऑफमेमरी त्रुटि क्यों नहीं मिलती है?

+14

इस प्रश्न से पूछने के लिए बेहतर जगह :) –

उत्तर

19

चूंकि आपका फ़ंक्शन tail recursion का उदाहरण है, इसलिए सबसे अधिक संभावना है कि सी कंपाइलर पुनरावृत्ति के लिए रिकर्सन को अनुकूलित कर रहा है, जिससे इसे बिना क्रैश किए असीमित रूप से लूप हो जाता है।

+0

हमारे पास जावा – GuruKulki

+0

में क्यों नहीं है, मुझे यकीन नहीं है कि 'क्यों', लेकिन जावा पूंछ कॉल अनुकूलन का समर्थन नहीं करता है, यही कारण है कि आपको जावा में त्रुटि मिलती है , लेकिन सी – pkaeding

+0

जावा कंपाइलर स्वचालित रूप से पूंछ रिकर्सन को पुनरावृत्ति में परिवर्तित नहीं करेगा, और यद्यपि यह कुछ जावा वीएम के लिए पूंछ रिकर्सन ऑप्टिमाइज़ेशन करने के लिए तकनीकी रूप से संभव है, लेकिन मुझे याद नहीं है कि किसी भी व्यक्ति के साथ व्यक्तिगत अनुभव हो रहा है। – RTBarnard

2

सी में, इसे पूंछ-रिकर्सिव कॉल के रूप में अनुकूलित किया जा सकता है। तो fun() पर कॉल वास्तव में स्वयं को कॉल नहीं करता है; यह सिर्फ फ़ंक्शन को पुनरारंभ करता है (एक गोटो की तरह)। दूसरे शब्दों में, कंपाइलर इसका मानता है जैसे कि यह इस तरह लिखा गया था:

void fun() { 
start: 
    goto start; 
} 

तो, ढेर बढ़ेगा नहीं।

9

कारण यह है कि सी कंपाइलर संभवत: पूंछ के रिकुसेव कॉल के रूप में इसका इलाज कर रहा है और इसलिए फ़ंक्शन के निष्पादन के लिए एक ढेर बनाने से परहेज कर रहा है। चूंकि कॉल के लिए कोई स्टैक नहीं बनाया गया है, यह रिकर्सन से एक साधारण अनंत लूप निष्पादन में बदल जाता है। आप इसे यह सिर पुनरावर्ती

int fun() { 1 + fun(); } 
-4

आप कुछ समय के बाद एक असामान्य कार्यक्रम समाप्ति मिल जाएगा बनाकर ढेर को बनाने के लिए मजबूर कर सकते हैं। आपके कोड में एक अनिश्चित रिकर्सन है और मज़ेदार प्रत्येक कॉल() स्टैक पर सशर्त बाइट डालता है। आपकी स्मृति और आपकी सीमा के आकार के आधार पर, आवेदन कम से कम कुछ 500 मिलियन कॉल के बाद समाप्त हो जाएगा। इसमें कुछ समय लग सकता है, लेकिन आपको एक असाधारण समाप्ति मिल जाएगी।

जावा वीएम कुछ स्तर तक रिकर्सन की गहराई को सीमित करता है, इसलिए यह जल्द ही समाप्त हो जाएगा।

+0

-1 यह सी संकलक पर निर्भर करता है। ऐसा कुछ भी नहीं है जो कहता है कि आपको असामान्य कार्यक्रम समाप्त करना है। यह सब संकलक में कोड पीढ़ी पर निर्भर करता है। –

+0

नहीं, यह संकलक निर्भर नहीं है। यह ऑपरेटिंग सिस्टम की एक विशेषता है। ओएस आवेदन के ढेर खंड का विस्तार करेगा और यह ढेर द्वारा कब्जा कर लिया गया पता स्थान में (कुछ बिंदु पर) दुर्घटनाग्रस्त हो जाएगा। जेएएपी - ओएस के कारण अपवाद (कम से कम यूनिक्स जैसे ओएसईएस के साथ)। –

+0

आप बिंदु खो रहे हैं: यदि कंपाइलर जेएलआर को जेएमपी द्वारा अपनी पूंछ रिकर्सन करते समय बदलता है, तो यह पूरी बात है कि लोग यहां बना रहे हैं: * स्टैक * पर कुछ भी नहीं चला है।क्या आप * एल 2: कूद एल 2 * कोड का उत्पादन करते हैं? यहां ढेर पर कोई धक्का नहीं है। बस एक जेएमपी। – SyntaxT3rr0r

2

यदि प्रोग्रामिंग भाषा के कार्यान्वयन में tail call optimization है, तो यह उस लूप को उस लूप में संकलित करेगा। वर्तमान जावा वीएम में पूंछ कॉल अनुकूलन नहीं है, इसलिए यह java.lang.StackOverflowError में समाप्त हो जाएगा।

शायद भविष्य जावा वी एम पूंछ कॉल अनुकूलन होगा में कुछ समय है, क्योंकि कार्यात्मक प्रोग्रामिंग भाषाओं जो JVM (स्काला, Clojure आदि) पर चलाने के यह से लाभ होगा (अभी कम से कम स्काला संकलक का अपना करता है direct recursion के लिए पूंछ कॉल अनुकूलन, लेकिन अप्रत्यक्ष रिकर्सन के लिए AFAIK नहीं)।

1

आपका सी कंपाइलर शायद पूंछ रिकर्सन का उपयोग कर उपयोग कर रहा है। प्रत्येक बार जब आप एक नए फ़ंक्शन में प्रवेश करते हैं तो कंप्यूटर स्टैक में एक प्रविष्टि जोड़ता है। यह प्रविष्टि बताती है कि सीपीयू को नियमित रूप से पूरा करने के बाद वापस कूदना चाहिए। अब ऊपर दिए गए मामले में, मज़े के अंदर मज़े() मज़े के लिए कॉल() फ़ंक्शन में अंतिम कॉल है, सी कंपाइलर स्टैक पुश को ऑप्टिमाइज़ कर सकता है और इसके बजाय टेलकॉल बना सकता है। आप वास्तव में इसका उपयोग कर सकते एक पाश बनाने के लिए:

int foo(int from, int to) 
{ 
    if (from == to) return from; 
    dosomething(); 
    from ++; 
    foo(from, to); 
} 

कई भाषाओं (उदाहरण के Erlang के लिए) सब पर छोरों की जरूरत नहीं है और इसके बजाय छोरों बनाने के लिए उपरोक्त विधि का उपयोग करें।

जावा पूंछ रिकर्सन का समर्थन नहीं करता है।

+1

क्या जावा समर्थन नहीं कर सकता है पूंछ-पुनरावृत्ति "अनुकूलन" है, लेकिन यह पूंछ-रिकर्सन – OscarRyz

+0

का समर्थन करता है, मैं सही खड़ा हूं ... हालांकि यह उपरोक्त विधि का समर्थन नहीं करता है, तो यह पूंछ-पुनरावृत्ति का समर्थन कैसे करता है? असेंबली दिखाने के लिए –

4

जैसा कि अन्य ने इंगित किया है कि यह सी कंपाइलर द्वारा किया गया पूंछ कॉल रिकर्सन ऑप्टिमाइज़ेशन है।हमेशा के रूप में, यह एक ठोस उदाहरण देखने में मदद करता है। किसी भी अनुकूलन सक्षम जीसीसी (v3.4.6) के बिना निम्नलिखित 86 विधानसभा कोड का उत्पादन: - मज़ा पुनरावर्ती कॉल

fun: 
    pushl %ebp 
    movl %esp, %ebp 
    call fun 
    leave 
    ret 
    .size fun, .-fun 

सूचना()। इस कार्यान्वित यदि यह अंत में अपनी ढेर और दुर्घटना अतिप्रवाह होगा, लेकिन -O2 जीसीसी में पैदा करता है: -

fun: 
     pushl %ebp 
     movl %esp, %ebp 
.L2: 
     jmp  .L2 
     .size fun, .-fun 

सूचना अंतहीन लूप एक वापसी शिक्षा के बिना? यह हमेशा के लिए हमेशा के लिए निष्पादित करेगा।

12

अन्य उत्तरदाता सही हैं कि कुछ कंपाइलर जादू है जो पूंछ रिकर्सन को पुनरावृत्ति में परिवर्तित करता है, हालांकि यह संकलक की अनुकूलन सेटिंग्स पर निर्भर करता है। उदाहरण के लिए जीसीसी में, हम gcc -S -O1 someFile.c (अपने कोड दिया गया है) के साथ संकलन करता है, तो, हम निम्नलिखित उत्पन्न विधानसभा मिलती है:, यह अभी भी कॉल उपयोग कर रहा है/छोड़/सेवानिवृत्त निर्देश एक वास्तविक समारोह कॉल प्रदर्शन करने के लिए

fun: 
.LFB2: 
     pushq %rbp 
.LCFI0: 
     movq %rsp, %rbp 
.LCFI1: 
     movl $0, %eax 
     call fun 
     leave 
     ret 
.LFE2: 
     .size fun, .-fun 

तो आप देख सकते , जो प्रक्रिया को मार डालेगा। एक बार जब आप gcc -S -O2 someFile.c के साथ आगे अनुकूलन प्रारंभ हम जादू हो रही शुरू:

fun: 
.LFB24: 
     .p2align 4,,10 
     .p2align 3 
.L2: 
     jmp  .L2 
.LFE24:  
     .size fun, .-fun 
     .p2align 4,,15 

यह अपने संकलक और अपने संकलक सेटिंग्स पर निर्भर करता है, इसलिए यह मित्र उनके साथ रहना मदद करता है।

+1

+1 और अभी भी कुछ प्रोग्रामर मौजूद हैं जो इसे समझते हैं। –

+0

+1 कंपाइलर के साथ दोस्त होने के लिए। :-) –

संबंधित मुद्दे