2012-06-25 26 views
28

मैं एक वेब पेज बनाने की कोशिश कर रहा हूं जिसके लिए मुझे जावास्क्रिप्ट में कई 100 एमबी डेटा फावड़ा जाना है। विभिन्न ब्राउज़रों के साथ मैं विभिन्न डेटा रकम पर "अधिकतम कॉल स्टैक आकार पार हो गया" त्रुटियों में चला जाता हूं।जावास्क्रिप्ट में ढेर बनाम ढेर? (अधिकतम कॉल स्टैक आकार पार हो गया)

क्या मैं इस कोड को अपने कोड से जाकर और कार्यों के अंदर स्थानीय चर को एक और वैश्विक दायरे में स्थानांतरित करने की कोशिश कर रहा हूं ताकि उन्हें ढेर के बजाय ढेर पर आवंटित करने का प्रयास किया जा सके? या जावास्क्रिप्ट में ये अवधारणाएं मौजूद नहीं हैं? (जहां तक ​​मुझे पता है, मेरे पास मेरे डेटा में कोई बड़ा रिकर्सिव लूप नहीं है, इसलिए यह वास्तव में कुछ विशाल तार/संख्या सरणी है जो त्रुटि उत्पन्न कर रहे हैं)

यदि यह संभव नहीं है , ब्राउजर से अधिक मेमोरी आरक्षित करने के तरीके पूछने के तरीके हैं?

+3

+1 रोचक पोस्ट के लिए है – pixelbobby

+4

आप से नहीं समझा गया है आप क्या देख रहे हैं । क्या हुआ है कि आपके पास एक रिकर्सिव फ़ंक्शन है, यानी एक ऐसा फ़ंक्शन जो स्वयं को कॉल करता है (या किसी अन्य फ़ंक्शन को कॉल करता है जो शायद पहले कॉल करता है) शायद दुर्घटना से। – Ben

+0

(संबंधित) http://stackoverflow.com/questions/6602864/stack-and-heap-in-v8-javascript –

उत्तर

16

जावास्क्रिप्ट में ढेर/ढेर में स्मृति का कोई अलगाव नहीं है। जो आप देख रहे हैं वह निम्नलिखित में से एक हो सकता है:

  1. रिकर्सन जो बहुत गहरा भाग गया। उस स्थिति में आपको इसे अधिक पुनरावृत्ति बनाने के लिए अपने एल्गोरिदम की समीक्षा करने की आवश्यकता होगी और कम रिकर्सन का उपयोग करें ताकि आप कॉल स्टैक ब्राउज़र द्वारा लगाए गए सीमाओं को हिट न करें।
  2. यदि आपके एल्गोरिदम में गहरी रिकर्सन नहीं है, तो यह अभी भी एक गहरी पर्याप्त कॉल हो सकती है, क्योंकि आपका कोड जेनरेट किया गया है।
  3. आखिरकार, कुछ इंजन फ़ंक्शन लुकअप के लिए किसी प्रकार के आंतरिक स्टैक पर फ़ंक्शन तर्क आवंटित किए गए नामों को आवंटित कर सकते हैं। यदि आप (या स्वचालित रूप से जेनरेट कोड) सचमुच हजारों स्थानीय चर या फ़ंक्शन में तर्कों का उपयोग करते हैं, तो यह इंजन-विशिष्ट सीमाओं को भी ओवरफ़्लो कर सकता है।
+0

मुझे यकीन है कि यह एक रिकर्सन मुद्दा नहीं है (मूल प्रश्न में संपादित देखें)। –

+0

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

+0

आप कम से कम आंशिक रूप से सही थे। मेरा कार्य वास्तव में सैकड़ों तर्क (वास्तव में लाखों) स्वीकार करता है। विवरण के लिए, नीचे देखें। लेकिन इसका मतलब यह है कि कम से कम सफारी और क्रोम के लिए फ़ंक्शन कॉल में दिए गए तर्कों के लिए स्मृति को ढेर/ढेर में अलग करना है। –

27

ठीक है, समस्या का पता लगाया। वास्तव में मेरे कोड में कोई रिकर्सन नहीं था। जावास्क्रिप्ट कार्यों को सैकड़ों तर्कों के साथ कॉल करना संभव है यदि वे "varargs" फ़ंक्शंस हैं उदाहरण के लिए <array>.splice(...), जो मेरा अपराधी था।

इसके अलावा: GWT जावा फंक्शन System.arraycopy(...) जावास्क्रिप्ट स्प्लिस फ़ंक्शन का उपयोग अधिक या कम चालाक तरीके से करते हुए लागू करता है।

splice लक्ष्य सरणी में डालने के लिए इनपुट तत्वों की मनमानी संख्या स्वीकार करता है। कॉल करने

var arguments = [index, howmany].concat(elements); 
Arrays.prototype.splice.apply(targetarray, arguments); 

यह बराबर है:

targetarray.splice(index, howmany, elements[0], elements[1], elements[2], ...); 

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

var elements = new Array(); 
for (i=0; i<126000; i++) elements[i] = 1; 
try { 
    var arguments = [0, 0].concat(elements); 
    Array.prototype.splice.apply(elements, arguments); 
    alert("OK"); 
} catch (err) { 
    alert(err.message); 
} 

इस स्क्रिप्ट का उपयोग करते हुए "बड़ी" का अर्थ है निम्नलिखित:

यहाँ एक छोटी स्क्रिप्ट है कि इस मुद्दे को दर्शाता है

  • क्रोम 19: तत्व शामिल हैं ~ 125,000 संख्या
  • सफारी 5.1 (विंडोज़ पर): तत्वों में ~ 65,000 संख्या
  • फ़ायरफ़ॉक्स 12: तत्वों में ~ 500,000 संख्याएं
  • शामिल हैं 10
  • ओपेरा 11.61: तत्वों में ~ 1,000,000 संख्या

और विजेता है: परिवर्तन के लिए इंटरनेट एक्सप्लोरर 8! यह फ़ंक्शन कॉल विफल होने से पहले, यह सभी सिस्टम मेमोरी का उपयोग कर सकता है।

एक ओर ध्यान दें: फ़ायरफ़ॉक्स और ओपेरा वास्तव में एक अलग (और अधिक उपयोगी) त्रुटि संदेश फेंक: Function.prototype.apply: argArray बहुत बड़ी

+3

ओउ, मुझे पता था कि यह संभव था, लेकिन उम्मीद थी कि कोई भी कभी कोशिश नहीं करेगा। –

+1

मजाकिया बात यह है कि: Google ने वास्तव में जीडब्ल्यूटी में इस दृष्टिकोण को मानकीकृत किया है ... :) यह जावास्क्रिप्ट में जावा की सिस्टम.एरेकॉपी को लागू करने का सबसे तेज़ तरीका है, लेकिन यह बड़े सरणी के लिए टूट जाता है ... और, लड़का, यह बग था खोजने के लिए एक सिर दर्द ... –

+0

नोट: यह जीडब्ल्यूटी 2.7 के लिए तय किया गया है: https://gwt.googlesource.com/gwt/+log/master/user/super/com/google/gwt/emul/java/ lang/system.java –

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