2016-06-02 6 views
8

मैं बड़ी 3 डी स्पैस सरणी संरचना को स्मृति में बहुत मेमोरी के बिना मेमोरी में रखने का एक तरीका ढूंढ रहा हूं। यहाँ मैं देशांतर की सरणियों के साथ एक प्रयोग किया है:कैसे एक बड़ी सरणी स्मृति आवंटित करता है?

using System; 
using System.Diagnostics; 
using System.Runtime; 

namespace ConsoleApp4 
{ 
    public class Program 
    { 
     static Process proc = Process.GetCurrentProcess(); 
     const int MB = 1024 * 1024; 
     const int IMAX = 5; 
     const int JMAX = 100000000; 
     public static void ShowTextWithMemAlloc(string text) 
     { 
      proc.Refresh(); 
      Console.WriteLine($"{text,-30}WS64:{proc.WorkingSet64/MB,5}MB PMS64:{proc.PrivateMemorySize64/MB,5}MB"); 
      Console.ReadKey(); 
     } 
     public static void Main(string[] args) 
     { 
      Console.Write(" "); 
      ShowTextWithMemAlloc("Start."); 
      long[] lArray = new long[IMAX * JMAX]; 
      long[] l1Array = new long[IMAX * JMAX]; 
      long[] l2Array = new long[IMAX * JMAX]; 
      long[] l3Array = new long[IMAX * JMAX]; 
      ShowTextWithMemAlloc("Arrays created."); 
      lArray[IMAX * JMAX - 1] = 5000; 
      l1Array[IMAX * JMAX - 1] = 5000; 
      l2Array[IMAX * JMAX - 1] = 5000; 
      l3Array[IMAX * JMAX - 1] = 5000; 
      ShowTextWithMemAlloc("Last elements accessed."); 
      for (var i=IMAX-1; i>= 0; i--) 
      { 
       for (var j=0; j<JMAX; j++) 
       { 
        lArray[i * JMAX + j] = i * JMAX + j; 
       } 
       ShowTextWithMemAlloc($"Value for row {i} assigned."); 
      } 
      //lArray = new long[5]; 
      //l1Array = null; 
      //l2Array = null; 
      //l3Array = null; 
      //GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; 
      //GC.Collect(); 
      //ShowTextWithMemAlloc($"GC.Collect done."); 
      ShowTextWithMemAlloc("Stop."); 
     } 
    } 
} 

आप इसे COMPlus_gcAllowVeryLargeObjects वातावरण चर सेट परीक्षण करना चाहते हैं - 1 के लिए (प्रोजेक्ट गुण> डीबग) या JMAX बदल जाते हैं। और यह उत्पादन होता है:

Start.      WS64: 14MB PMS64: 8MB 
Arrays created.    WS64: 15MB PMS64:15360MB 
Last elements accessed.  WS64: 15MB PMS64:15360MB 
Value for row 4 assigned.  WS64: 779MB PMS64:15360MB 
Value for row 3 assigned.  WS64: 1542MB PMS64:15360MB 
Value for row 2 assigned.  WS64: 2305MB PMS64:15361MB 
Value for row 1 assigned.  WS64: 3069MB PMS64:15361MB 
Value for row 0 assigned.  WS64: 3832MB PMS64:15362MB 
Stop.       WS64: 3844MB PMS64:15325MB 

जब मैं देख रहा हूँ कार्य प्रबंधक में स्मृति की खपत Process.WorkingSet64 में इस तरह है। वास्तविक संख्या क्या है? असाइनमेंट पर आवंटित स्मृति क्यों है? क्या वास्तव में एक सरणी आवंटित स्मृति है? एक सरणी एक सरणी है? एलियंस मौजूद हैं? (नाटकीय पृष्ठभूमि संगीत)

प्रकरण 2: हम एक छोटा सा परिवर्तन करना:

  //lArray[i * JMAX + j] = i * JMAX + j; 
      var x= lArray[i * JMAX + j]; 

और कुछ भी नहीं परिवर्तन (उत्पादन में)। मौजूदा और nonexistent के बीच अंतर कहां है? (अधिक नाटकीय पृष्ठभूमि संगीत) अब हम रहस्यमय लोगों में से एक के जवाब का इंतजार कर रहे हैं (उनके पास उनके नाम के तहत कुछ संख्या और एक छोटा 'के' है)।

प्रकरण 3: एक और परिवर्तन:

//lArray[IMAX * JMAX - 1] = 5000; 
    //l1Array[IMAX * JMAX - 1] = 5000; 
    //l2Array[IMAX * JMAX - 1] = 5000; 
    //l3Array[IMAX * JMAX - 1] = 5000; 
    //ShowTextWithMemAlloc("Last elements accessed."); 
    long newIMAX = IMAX-3; 
    long newJMAX = JMAX/10; 
    for (var i=0; i<newIMAX; i++) 
    { 
     for (var j=0; j<newJMAX; j++) 
     { 
      lArray[i * newJMAX + j] = i * newJMAX + j; 
      //var x= lArray[i * JMAX + j]; 
     } 
     //ShowTextWithMemAlloc($"Value for row {i} assigned."); 
    } 
    ShowTextWithMemAlloc($"{newIMAX*newJMAX} values assigned."); 

उत्पादन:

Start.        WS64: 14MB PMS64: 8MB 
Arrays created.     WS64: 15MB PMS64:15369MB 
20000000 values assigned.   WS64: 168MB PMS64:15369MB 
Stop.        WS64: 168MB PMS64:15369MB 

PMS64 के लिए एक सरणी (15,369-8)/4 = 3840MB यह नहीं विरल सरणी, लेकिन आंशिक रूप से भरे सरणी;)। मैं इस 168 एमबी पूर्ण का उपयोग कर रहा हूँ।

कुछ प्रश्नों के उत्तर "आप सटीक आकार का उपयोग क्यों नहीं करते?"। क्योंकि मुझे यह नहीं पता? डेटा कई उपयोगकर्ता परिभाषित एसक्यूएल से आ सकता है। "आप इसका आकार क्यों नहीं बदलते?"। आकार बदलें एक नई सरणी बनाते हैं और मूल्यों की प्रतिलिपि बनाते हैं। यह प्रतिलिपि बनाने, स्मृति और अंत में बुराई जीसी आता है और आपको खाता है।

क्या मैंने स्मृति बर्बाद कर दी थी। (मुझे याद नहीं है। एलियंस ?!) और जब हाँ, कितना? 0, (3840-168) एमबी या (1536 9-8-168) एमबी?

उपसंहार:

एक टिप्पणी एक टिप्पणी या एक जवाब है?

असीमित स्मृति वास्तव में संगत स्मृति है?

क्या उत्तर उत्तर देते हैं? रहस्यमय। (more music)

(स्कली: मुलडर, टोड सिर्फ आसमान से गिर गया मुलडर:। मुझे लगता है कि अपने पैराशूट नहीं खुला था)

आप सभी धन्यवाद!

+3

* क्या वास्तव में एक सरणी आवंटित स्मृति है? एक सरणी एक सरणी है? क्या एलियंस मौजूद हैं? * हां। हाँ। शायद, लेकिन वे * दूर * हैं। –

+1

मुझे संदेह है कि (वास्तव में दिलचस्प) प्रश्न है कि आप याद कर सकते हैं "क्या स्मृति वास्तव में स्मृति है"? ... और शायद "ठीक है, लेकिन जब स्मृति स्मृति है, असीमित स्मृति वास्तव में संगत स्मृति है?" - नहीं, मुझे जवाब लिखने के लिए वास्तव में पर्याप्त जानकारी नहीं है। – moreON

उत्तर

6

कार्य सेट आवंटित स्मृति की मात्रा नहीं है। यह उन पृष्ठों का सेट है जो वर्तमान में प्रक्रिया के लिए उपलब्ध हैं। विंडोज़ इसके आसपास विभिन्न नीतियों को लागू करता है और आम तौर पर संख्या को समझना मुश्किल होता है।

यहां, स्मृति की संभावना ओएस से शून्य के रूप में अनुरोध की गई थी। किसी पृष्ठ की पहली पहुंच वास्तव में एक शून्य पृष्ठ उपलब्ध कराती है।

आपको निजी बाइट्स देखना चाहिए।

आप कम से कम .NET arrays आवंटित नहीं कर सकते हैं। शायद, आपको कुछ डेटा संरचना को नियोजित करना चाहिए जो एक स्पैस सरणी की छाप प्रदान करता है।

क्या वास्तव में एक सरणी आवंटित स्मृति है?

हाँ, सीएलआर और .NET कोड चल रहे परिप्रेक्ष्य से हां। ओएस पहले पढ़ने या लिखने वाले पृष्ठों में आलसी रूप से गलती जैसे चाल चल सकता है।

"एपिसोड 2" के लिए उत्तर यह है कि पढ़ने के साथ-साथ लिखने के लिए दोषपूर्ण होता है। मैं काफी नहीं करता कि एपिसोड 3 क्या करता है लेकिन मुझे लगता है कि यह कम पृष्ठों को छूता है।

मैं स्मृति बर्बाद

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

एक चरम मामले में, यदि आप 1TB आवंटित करते हैं तो आपको 1TB से अधिक होने के लिए रैम और पेजिंग फ़ाइल आकार की राशि की आवश्यकता होती है, भले ही उस स्थान में से कोई भी उपयोग न हो।

स्मृति मैप की गई फ़ाइलों का उपयोग करने पर विचार करें। यहां, फ़ाइल बैकिंग स्टोर है और रैम को कैश की तरह माना जाता है। यह बिल्कुल वही व्यवहार करेगा।

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