एक गतिशील रूप से आवंटित सरणी के लिए आदर्श विकास दर क्या है?


84

C ++ में std :: वेक्टर और जावा में ArrayList है, और कई अन्य भाषाओं में गतिशील रूप से आवंटित सरणी का अपना रूप है। जब एक डायनामिक एरे अंतरिक्ष से बाहर निकलता है, तो यह एक बड़े क्षेत्र में पुनः प्राप्त हो जाता है और पुराने मानों को नए एरे में कॉपी किया जाता है। इस तरह के एक सरणी के प्रदर्शन के लिए एक प्रश्न यह है कि सरणी आकार में कितनी तेजी से बढ़ती है। यदि आप हमेशा केवल वर्तमान पुश को फिट करने के लिए ही बड़े होते हैं, तो आप हर बार पुनः प्राप्ति करेंगे। तो यह सरणी आकार को दोगुना करने के लिए समझ में आता है, या इसे 1.5x से गुणा करें।

क्या एक आदर्श विकास कारक है? 2x? 1.5x? आदर्श रूप से मेरा मतलब है गणितीय रूप से उचित, सर्वश्रेष्ठ संतुलन प्रदर्शन और व्यर्थ स्मृति। मुझे लगता है कि सैद्धांतिक रूप से, यह देखते हुए कि आपके आवेदन में किसी भी संभावित वितरण का धक्का हो सकता है कि यह कुछ हद तक निर्भर है। लेकिन मैं यह जानने के लिए उत्सुक हूं कि क्या कोई ऐसा मूल्य है जो "आमतौर पर" सबसे अच्छा है, या कुछ कठोर अवरोधों में सबसे अच्छा माना जाता है।

मैंने सुना है कि इस पर एक पेपर कहीं है, लेकिन मैं इसे खोजने में असमर्थ हूं।

जवाबों:


44

यह पूरी तरह से उपयोग के मामले पर निर्भर करेगा। क्या आप उस समय के बारे में अधिक देखभाल करते हैं जो डेटा की प्रतिलिपि बनाने में बर्बाद हो जाता है (और एरेक्लोलेटिंग सरणियाँ) या अतिरिक्त मेमोरी? सरणी कितने समय तक चलने वाली है? यदि यह लंबे समय तक रहने वाला नहीं है, तो एक बड़े बफर का उपयोग करना एक अच्छा विचार हो सकता है - जुर्माना अल्पकालिक है। यदि यह चारों ओर लटका हुआ है (उदाहरण के लिए जावा में, पुरानी और पुरानी पीढ़ियों में जा रहा है) जो स्पष्ट रूप से एक दंड का अधिक है।

"आदर्श विकास कारक" जैसी कोई चीज नहीं है। यह सिर्फ सैद्धांतिक रूप से आवेदन पर निर्भर नहीं है, यह निश्चित रूप से आवेदन पर निर्भर है।

2 एक बहुत ही सामान्य वृद्धि कारक है - मुझे पूरा यकीन है कि क्या ArrayListऔर List<T>.NET उपयोग में है। ArrayList<T>जावा में 1.5 का उपयोग करता है।

EDIT: जैसा कि Erich बताता है, Dictionary<,>.NET में "दोगुना आकार फिर अगले प्राइम नंबर तक बढ़ जाता है" का उपयोग करता है ताकि हैश मान को बाल्टी के बीच यथोचित वितरित किया जा सके। (मुझे यकीन है कि मैंने हाल ही में प्रलेखन को यह सुझाव देते हुए देखा है कि प्राइम्स वास्तव में हैश बकेट के वितरण के लिए महान नहीं हैं, लेकिन यह आपके उत्तर के लिए तर्क है।)


104

मुझे याद है कि कई साल पहले 1.5 को दो से अधिक क्यों पसंद किया जाता है, कम से कम C ++ पर लागू होता है (यह संभवतः प्रबंधित भाषाओं पर लागू नहीं होता है, जहां रनटाइम सिस्टम वसीयत में ऑब्जेक्ट्स को स्थानांतरित कर सकता है)।

तर्क यह है:

  1. कहते हैं कि आप 16-बाइट आवंटन के साथ शुरू करते हैं।
  2. जब आपको अधिक आवश्यकता होती है, तो आप 32 बाइट्स आवंटित करते हैं, फिर 16 बाइट्स मुक्त करते हैं। यह एक 16-बाइट छेद को स्मृति में छोड़ देता है।
  3. जब आपको अधिक आवश्यकता होती है, तो आप 32 बाइट को मुक्त करते हुए 64 बाइट आवंटित करते हैं। यह एक 48-बाइट छेद (यदि 16 और 32 आसन्न थे) को छोड़ देता है।
  4. जब आपको अधिक आवश्यकता होती है, तो आप 64 बाइट को खाली करते हुए 128 बाइट आवंटित करते हैं। यह एक 112-बाइट छेद छोड़ता है (सभी पिछले आवंटन समीप हैं)।
  5. और इसलिए और आगे।

विचार यह है कि, 2x विस्तार के साथ, समय का कोई मतलब नहीं है कि परिणामी छेद कभी भी अगले आवंटन के लिए पुन: उपयोग करने के लिए पर्याप्त बड़ा होने वाला है। 1.5x आवंटन का उपयोग करते हुए, हमारे पास इसके बजाय:

  1. शुरुआत 16 बाइट्स से करें।
  2. जब आपको अधिक आवश्यकता होती है, तो 24 बाइट्स आवंटित करें, फिर 16 को मुक्त करें, 16-बाइट छेद छोड़कर।
  3. जब आपको अधिक आवश्यकता होती है, तो 36 बाइट्स आवंटित करें, फिर 24 को मुक्त करें, एक 40-बाइट छेद छोड़कर।
  4. जब आपको अधिक आवश्यकता होती है, तो 54 बाइट्स आवंटित करें, फिर 36 को मुक्त करें, जिसमें 76-बाइट छेद हो।
  5. जब आपको अधिक आवश्यकता होती है, तो 81 बाइट्स आवंटित करें, फिर 54 को मुक्त करें, 130-बाइट छेद छोड़कर।
  6. जब आपको अधिक आवश्यकता होती है, तो 130-बाइट छेद से 122 बाइट्स (राउंडिंग अप) का उपयोग करें।

5
एक यादृच्छिक फ़ोरम पोस्ट मुझे मिला ( objectmix.com/c/… ) इसी तरह से। एक पोस्टर का दावा है कि (1 + sqrt (5)) / 2 पुन: उपयोग के लिए ऊपरी सीमा है।
नाफ़ जूल

19
यदि वह दावा सही है, तो phi (== (1 + sqrt (5)) / 2) वास्तव में उपयोग करने के लिए इष्टतम संख्या है।
क्रिस जस्टर-यंग

1
मुझे यह उत्तर पसंद है क्योंकि यह 1.5x बनाम 2x के औचित्य को प्रकट करता है, लेकिन जॉन ने जिस तरह से यह कहा था उसके लिए तकनीकी रूप से सबसे सही है। मुझे अभी पूछना चाहिए था कि अतीत में 1.5 की सिफारिश क्यों की गई है: पी
जोसेफ गार्विन 15'10

6
फेसबुक FBVector कार्यान्वयन में 1.5 का उपयोग करता है, यहां लेख बताता है कि 1.5 FBVector के लिए इष्टतम क्यों है।
csharpfolk

2
@jackmott अधिकार, जैसा कि मेरे उत्तर में उल्लेख किया गया है: "यह संभवतः प्रबंधित भाषाओं पर लागू नहीं होता है, जहां रनटाइम सिस्टम वसीयत में वस्तुओं को स्थानांतरित कर सकता है"।
क्रिस जस्टर-यंग

48

आदर्श रूप में ( n → ∞ की सीमा में ), यह स्वर्णिम अनुपात है : 18 = 1.618 ...

व्यवहार में, आप कुछ करीब चाहते हैं, जैसे 1.5।

कारण यह है कि आप पुराने मेमोरी ब्लॉकों का पुन: उपयोग करने में सक्षम होना चाहते हैं, कैशिंग का लाभ उठाने के लिए और लगातार ओएस बनाने से बचने के लिए आपको अधिक मेमोरी पेज देते हैं। समीकरण जिसे आप यह सुनिश्चित करने के लिए हल करेंगे कि यह x n - 1 - 1 = x n + 1 - x n तक कम हो जाता है , जिसका समाधान बड़े n के लिए x = x तक पहुंचता है ।


15

इस तरह के सवालों का जवाब देने पर एक दृष्टिकोण सिर्फ "धोखा" देना है और यह देखना है कि लोकप्रिय पुस्तकालय क्या करते हैं, इस धारणा के तहत कि व्यापक रूप से उपयोग किया जाने वाला पुस्तकालय, बहुत कम से कम, कुछ भयानक नहीं कर रहा है।

तो बस बहुत जल्दी से जाँच कर रहा है, रूबी (1.9.1-p129) एक सरणी में संलग्न होने पर 1.5x का उपयोग करता है, और पायथन (2.6.2) 1.125x प्लस एक स्थिर (में Objects/listobject.c) का उपयोग करता है :

/* This over-allocates proportional to the list size, making room
 * for additional growth.  The over-allocation is mild, but is
 * enough to give linear-time amortized behavior over a long
 * sequence of appends() in the presence of a poorly-performing
 * system realloc().
 * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
 */
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);

/* check for integer overflow */
if (new_allocated > PY_SIZE_MAX - newsize) {
    PyErr_NoMemory();
    return -1;
} else {
    new_allocated += newsize;
}

newsizeऊपर सरणी में तत्वों की संख्या है। ध्यान दें कि newsizeइसमें जोड़ा गया है new_allocated, इसलिए बिटशिफ्ट्स और टर्नरी ऑपरेटर के साथ अभिव्यक्ति वास्तव में केवल ओवर-आवंटन की गणना कर रही है।


तो यह सरणी को n से n + (n / 8 + (n <9? 3: 6)) तक बढ़ाता है, जिसका अर्थ है कि विकास कारक, प्रश्न की शब्दावली में, 1.25x (साथ ही एक स्थिर) है।
श्रीवत्सआर

यह 1.125x प्लस एक स्थिर नहीं होगा?
जेसन क्रेइटन

10

मान लें कि आप सरणी का आकार बढ़ाते हैं x। तो मान लें कि आप आकार से शुरू करते हैं T। अगली बार जब आप सरणी बढ़ाएँगे तो उसका आकार होगा T*x। फिर ऐसा ही होगा T*x^2

यदि आपका लक्ष्य पहले बनाई गई मेमोरी का पुन: उपयोग करने में सक्षम होना है, तो आप यह सुनिश्चित करना चाहते हैं कि आपके द्वारा आवंटित नई मेमोरी पिछली मेमोरी के योग से कम है जिसे आपने डील किया था। इसलिए, हमारे पास यह असमानता है:

T*x^n <= T + T*x + T*x^2 + ... + T*x^(n-2)

हम दोनों तरफ से टी हटा सकते हैं। तो हम इसे प्राप्त करते हैं:

x^n <= 1 + x + x^2 + ... + x^(n-2)

अनौपचारिक रूप से, हम जो कहते हैं, वह यह है कि nthहम चाहते हैं कि हमारी सभी पूर्ववर्ती मेमोरी को nth आवंटन में मेमोरी की आवश्यकता के बराबर या उससे अधिक हो, ताकि हम पहले से डील की गई मेमोरी का पुन: उपयोग कर सकें।

उदाहरण के लिए, यदि हम इसे तीसरे चरण (यानी, n=3) पर करना चाहते हैं, तो हमारे पास है

x^3 <= 1 + x 

यह समीकरण सभी x के लिए सही है जैसे कि 0 < x <= 1.3(लगभग)

देखें कि अलग-अलग n के नीचे हमें क्या मिलता है:

n  maximum-x (roughly)

3  1.3

4  1.4

5  1.53

6  1.57

7  1.59

22 1.61

ध्यान दें कि बढ़ रही कारक की तुलना में कम हो गया है 2के बाद से x^n > x^(n-2) + ... + x^2 + x + 1 for all x>=2


आप यह दावा करते हैं कि आप पहले से ही 2 आवंटन पर पहले से ही अस्वीकृत मेमोरी का पुनः उपयोग 1.5 के कारक के साथ कर सकते हैं। यह सच नहीं है (ऊपर देखें)। मुझे पता है अगर मैं तुम्हें गलत समझा।
23

2 आवंटन पर आप 1.5 * 1.5 * T = 2.25 * T आवंटित कर रहे हैं, जबकि कुल सौदा आप तब तक कर रहे हैं जब तक कि T + 1.5 * T = 2.5 * T। तो 2.5 2.25 से अधिक है।
CEGRD

आह, मुझे और अधिक ध्यान से पढ़ना चाहिए; आप सभी कहते हैं कि कुल मिलाई गई मेमोरी nth आवंटन में आवंटित मेमोरी से अधिक होगी, कि आप इसे nth आवंटन में पुनः उपयोग कर सकते हैं।
awx

4

यह वास्तव में निर्भर करता है। कुछ लोग इष्टतम संख्या खोजने के लिए सामान्य उपयोग के मामलों का विश्लेषण करते हैं।

मैंने देखा है 1.5x 2.0x phi x, और 2 की शक्ति का उपयोग करने से पहले।


फी! यह उपयोग करने के लिए एक अच्छी संख्या है। मुझे अभी से इसका इस्तेमाल करना शुरू कर देना चाहिए। धन्यवाद! +1
क्रिस जेस्टर-यंग

मुझे समझ नहीं आया ... क्यों फ़ि? इसमें ऐसा क्या गुण है जो इसे इसके लिए उपयुक्त बनाता है?
जेसन क्रेइटन

4
@ जेसन: फी एक फाइबोनैचि अनुक्रम के लिए बनाता है, इसलिए अगला आवंटन आकार वर्तमान आकार और पिछले आकार का योग है। यह मध्यम विकास दर के लिए अनुमति देता है, 1.5 से तेज, लेकिन 2 नहीं (मेरी पोस्ट को क्यों = 2 के रूप में देखें, यह एक अच्छा विचार नहीं है, कम से कम अप्रबंधित भाषाओं के लिए)।
क्रिस जस्टर-यंग

1
@ जेसन: इसके अलावा, मेरी पोस्ट के लिए एक टिप्पणीकार के अनुसार, कोई भी संख्या> फी वास्तव में एक बुरा विचार है। मैंने स्वयं इस बात की पुष्टि करने के लिए गणित नहीं किया है, इसलिए इसे नमक के दाने के साथ लें।
क्रिस जस्टर-यंग

2

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

साधारण निरंतर एकाधिक का उपयोग करने का कारण, स्पष्ट रूप से ऐसा है कि प्रत्येक परिशिष्ट ने निरंतर समय में संशोधन किया है। लेकिन इसका मतलब यह नहीं है कि आप छोटे आकार के लिए अलग (बड़े) अनुपात का उपयोग नहीं कर सकते।

स्कैला में, आप मानक लाइब्रेरी हैश टेबल्स के लिए लोडफ़ैक्टर को ओवरराइड कर सकते हैं जो एक फ़ंक्शन के साथ वर्तमान आकार को देखता है। अजीब तरह से, रिसाइकिलिंग सरणियां सिर्फ दोगुनी होती हैं, जो कि ज्यादातर लोग व्यवहार में करते हैं।

मुझे किसी भी दोहरीकरण (या 1.5 * आईएनजी) सरणियों का पता नहीं है जो वास्तव में मेमोरी त्रुटियों से बाहर निकलते हैं और उस मामले में कम बढ़ते हैं। ऐसा लगता है कि यदि आपके पास एक बहुत बड़ा सरणी है, तो आप ऐसा करना चाहते हैं।

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


2

एक और दो सेंट

  • अधिकांश कंप्यूटरों में वर्चुअल मेमोरी होती है! भौतिक मेमोरी में आपके पास हर जगह यादृच्छिक पृष्ठ हो सकते हैं जो आपके प्रोग्राम की वर्चुअल मेमोरी में एक एकल सन्निहित स्थान के रूप में प्रदर्शित होते हैं। अप्रत्यक्ष का समाधान हार्डवेयर द्वारा किया जाता है। वर्चुअल मेमोरी थकावट 32 बिट सिस्टम पर एक समस्या थी, लेकिन यह वास्तव में अब कोई समस्या नहीं है। तो छेद भरना कोई चिंता का विषय नहीं है (विशेष वातावरण को छोड़कर)। विंडोज 7 के बाद से भी Microsoft अतिरिक्त प्रयास के बिना 64 बिट का समर्थन करता है। @ २०११
  • O (1) किसी भी r > 1 कारक के साथ पहुँच जाता है। समान गणितीय प्रमाण न केवल पैरामीटर के रूप में 2 के लिए काम करता है।
  • r = 1.5 की गणना की जा सकती है old*3/2ताकि फ्लोटिंग पॉइंट ऑपरेशंस की कोई आवश्यकता न हो। (मैं कहता हूं /2क्योंकि कंपाइलर इसे जेनरेट किए गए असेंबली कोड में बिट शिफ्टिंग के साथ बदल देंगे अगर वे फिट होते हैं।)
  • MSVC के लिए चला गया r = 1.5 के , इसलिए कम से कम एक प्रमुख संकलक है जो अनुपात के रूप में 2 का उपयोग नहीं करता है।

जैसा कि किसी ने उल्लेख किया है 2 8 से बेहतर महसूस करता है। और 2 भी 1.1 से बेहतर महसूस करता है।

मेरी भावना यह है कि 1.5 एक अच्छा डिफ़ॉल्ट है। इसके अलावा यह विशिष्ट मामले पर निर्भर करता है।


3
n + n/2ओवरफ्लो में देरी करने के लिए इसका इस्तेमाल करना बेहतर होगा । का उपयोग करते हुए n*3/2आधे से अपने संभव क्षमता में कटौती।
ओकाकोडर

@owacoder सच। लेकिन जब n * 3 फिट नहीं है, लेकिन n * 1.5 फिट है तो हम बहुत सारी मेमोरी के बारे में बात कर रहे हैं। यदि n 32 बिट अनसेंडेंड है तो n * 3 ओवरफ्लो होता है जब n 4G / 3 होता है, अर्थात 1.333G लगभग। वह एक बहुत बड़ी संख्या है। यह एक आवंटन में करने के लिए स्मृति की बहुत है। कभी भी अधिक अगर तत्व 1 बाइट नहीं हैं, लेकिन उदाहरण के लिए 4 बाइट्स प्रत्येक। उपयोग के मामले के बारे में आश्चर्य ...
नोटिनिस्टल

3
यह सच है कि यह एक किनारे का मामला हो सकता है, लेकिन किनारे के मामले वही हैं जो आमतौर पर काटते हैं। संभव अतिप्रवाह या अन्य व्यवहारों की तलाश करने की आदत में पड़ना, जो एक बेहतर डिजाइन पर संकेत कर सकता है, कभी भी एक बुरा विचार नहीं है, भले ही यह वर्तमान में दूर की कौड़ी लग सकता है। एक उदाहरण के रूप में 32-बिट पते लें। अब हमें 64 की आवश्यकता है ...
उल्लू को

0

मैं जॉन स्कीट से सहमत हूं, यहां तक ​​कि मेरे सिद्धांतकार मित्र भी जोर देते हैं कि 2x को कारक स्थापित करते समय यह ओ (1) साबित हो सकता है।

सीपीयू समय और मेमोरी के बीच का अनुपात प्रत्येक मशीन पर अलग है, और इसलिए कारक बस के रूप में अलग-अलग होगा। यदि आपके पास गीगाबाइट्स ऑफ रैम और धीमी सीपीयू वाली मशीन है, तो तत्वों को एक नए सरणी में कॉपी करना एक तेज़ मशीन की तुलना में बहुत अधिक महंगा है, जिसमें बदले में कम मेमोरी हो सकती है। यह एक ऐसा सवाल है जिसका उत्तर सिद्धांत में दिया जा सकता है, एक समान कंप्यूटर के लिए, जो वास्तविक परिदृश्य में आपकी बिल्कुल मदद नहीं करता है।


2
विस्तृत करने के लिए, सरणी आकार को दोगुना करने का अर्थ है कि आपको एमोटाइज़्ड ओ (1) आवेषण मिलता है। विचार यह है कि हर बार जब आप एक तत्व सम्मिलित करते हैं, तो आप पुराने सरणी से एक तत्व को भी कॉपी करते हैं। मान लें कि आपके पास आकार एम की एक सरणी है , जिसमें एम तत्व हैं। जब तत्व m + 1 जोड़ते हैं , तो कोई स्थान नहीं होता है, इसलिए आप आकार की एक नई सरणी 2m आवंटित करते हैं । सभी पहले m तत्वों को कॉपी करने के बजाय , आप हर बार जब आप एक नया तत्व सम्मिलित करते हैं, तो एक को कॉपी करते हैं। यह विचरण को कम करता है (मेमोरी के आवंटन के लिए सहेजें), और एक बार जब आपने 2 मी तत्व सम्मिलित किया है, तो आपने पुराने एरे से सभी तत्वों को कॉपी कर लिया होगा।
10

-1

मुझे पता है कि यह एक पुराना सवाल है, लेकिन कई चीजें हैं जो सभी को याद आ रही हैं।

सबसे पहले, यह 2 से गुणा है: आकार << 1. यह 1 और 2 के बीच किसी भी चीज से गुणा है : int (फ्लोट (आकार) * x), जहां x संख्या है, * अस्थायी बिंदु गणित है, और प्रोसेसर है फ्लोट और इंट के बीच कास्टिंग के लिए अतिरिक्त निर्देश चलाने के लिए। दूसरे शब्दों में, मशीन के स्तर पर, दोहरीकरण एकल, नए आकार को खोजने के लिए बहुत तेज़ निर्देश देता है। 1 और 2 के बीच किसी चीज से गुणा करने के लिए कम से कम आवश्यकता होती हैएक फ्लोट को आकार देने के लिए एक निर्देश, एक निर्देश गुणा करने के लिए (जो फ्लोट गुणन है, इसलिए यह संभवतः कम से कम दो बार कई चक्रों को लेता है, यदि 4 या 8 बार भी नहीं है), और एक निर्देश इंट में वापस डालने के लिए। और यह मान लेता है कि आपका प्लेटफ़ॉर्म विशेष रजिस्टरों के उपयोग की आवश्यकता के बजाय सामान्य उद्देश्य रजिस्टरों पर फ्लोट गणित का प्रदर्शन कर सकता है। संक्षेप में, आपको प्रत्येक आबंटन के लिए गणित से अपेक्षा करनी चाहिए कि वह साधारण बायीं पाली के रूप में कम से कम 10 बार ले। यदि आप वास्तविक डेटा के दौरान बहुत अधिक डेटा कॉपी कर रहे हैं, तो इससे बहुत फर्क नहीं पड़ सकता है।

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

मेरे सवाल का जवाब? नहीं, कोई आदर्श संख्या नहीं है। यह इतना विशिष्ट अनुप्रयोग है कि कोई वास्तव में कोशिश भी नहीं करता है। यदि आपका लक्ष्य आदर्श स्मृति उपयोग है, तो आप भाग्य से बहुत बाहर हैं। प्रदर्शन के लिए, कम लगातार आवंटन बेहतर हैं, लेकिन अगर हम बस उसी के साथ गए, तो हम 4 या 8 से गुणा कर सकते हैं! बेशक, जब फ़ायरफ़ॉक्स एक शॉट में 1GB से 8GB का उपयोग करने के लिए कूदता है, तो लोग शिकायत करने जा रहे हैं, इसलिए इसका कोई मतलब भी नहीं है। हालांकि मैं अंगूठे के कुछ नियम बताऊंगा:

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

इसे उखाड़ फेंकें नहीं। यदि आपने अभी 4 घंटे बिताए हैं, तो यह पता लगाने की कोशिश करें कि कुछ ऐसा कैसे करें जो पहले से ही किया गया है, तो आपने अपना समय बर्बाद किया। पूरी तरह से ईमानदारी से, अगर * 2 से बेहतर विकल्प होता, तो दशकों पहले C ++ वेक्टर क्लास (और कई अन्य स्थानों) में किया जाता।

अंत में, यदि आप वास्तव में अनुकूलन करना चाहते हैं, तो छोटे सामान को पसीना न करें। अब दिन, कोई भी 4KB मेमोरी के बर्बाद होने की परवाह नहीं करता है, जब तक कि वे एम्बेडेड सिस्टम पर काम नहीं कर रहे हैं। जब आप 1GB और 10MB के बीच की वस्तुओं के 1GB तक पहुंच जाते हैं, तो दोहरीकरण संभवतया बहुत अधिक होता है (मेरा मतलब है, कि 100 और 1,000 वस्तुओं के बीच है)। यदि आप अपेक्षित विस्तार दर का अनुमान लगा सकते हैं, तो आप इसे एक निश्चित बिंदु पर रैखिक विकास दर तक ले जा सकते हैं। यदि आप प्रति मिनट 10 ऑब्जेक्ट की अपेक्षा करते हैं, तो प्रति चरण 5 से 10 ऑब्जेक्ट आकार में बढ़ रहा है (एक मिनट में हर 30 सेकंड में) शायद ठीक है।

यह सब क्या है, इसके बारे में सोचें, इसे खत्म न करें, जो आप कर सकते हैं उसे अनुकूलित करें, और यदि आवश्यक हो तो अपने आवेदन (और मंच) के लिए अनुकूलित करें।


11
बिल्कुल n + n >> 1वैसा ही है 1.5 * n। आपके द्वारा सोचा जा सकने वाले प्रत्येक व्यावहारिक विकास कारक के लिए समान चालें आना काफी आसान है।
ब्योर्न लिंडक्विस्ट

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

@ रेबेक - हालांकि कुछ कार्यक्रम हो सकते हैं जो एक या दो निर्देशों द्वारा समय भिन्नता के प्रति संवेदनशील होते हैं, यह बहुत कम संभावना है कि कोई भी प्रोग्राम जो गतिशील वास्तविकताओं का उपयोग करता है, कभी भी चिंतित होगा। यदि इसे समय पर नियंत्रित करने की आवश्यकता है, तो यह संभवतः इसके बजाय सांख्यिकीय रूप से आवंटित भंडारण का उपयोग करेगा।
उल्लू का पट्ठा

मैं गेम करता हूं, जहां एक या दो निर्देश गलत स्थान पर महत्वपूर्ण प्रदर्शन अंतर कर सकते हैं। यदि स्मृति आवंटन को अच्छी तरह से संभाला जाता है, तो कहा जाता है, यह कुछ निर्देशों के लिए अक्सर पर्याप्त नहीं होना चाहिए ताकि अंतर हो सके।
रायबेक आरथर्डर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.