2011-04-19 12 views
14

मैं एक आंतरिक वर्ग का उपयोग कर रहा हूं जो हैश मैप का उप-वर्ग है। मेरे पास String कुंजी और double[] मान के रूप में है। मैं double[] प्रति 200 युगल स्टोर करता हूं। मुझे कुंजी, पॉइंटर्स और युगल स्टोर करने के लिए लगभग 700   एमबी का उपयोग करना चाहिए। हालांकि, स्मृति विश्लेषण से पता चलता है कि मुझे उससे अधिक की आवश्यकता है (थोड़ा 2   जीबी)।जावा में Serializable, क्लोनेबल और मेमोरी उपयोग

TIJmp (प्रोफाइलिंग टूल) का उपयोग करके मैंने देखा कि char[] था जो कुल स्मृति का लगभग आधा उपयोग कर रहा था। टीआईजेएम ने कहा कि char[]Serializable और Cloneable से आया था। इसमें मान फोंट की सूची और संदेशों और एकल वर्णों के डिफ़ॉल्ट पथ से लेकर थे।

JVM में Serializable का सटीक व्यवहार क्या है? क्या यह हर समय "लगातार" प्रतिलिपि रखते हुए, मेरी स्मृति पदचिह्न के आकार को दोगुना कर रहा है? मैं जेवीएम को मेमोरी होग में घुमाने के बिना रनटाइम पर ऑब्जेक्ट की द्विआधारी प्रतियां कैसे लिख सकता हूं?

पीएस: विधि जहां मेमोरी खपत सबसे अधिक बढ़ जाती है वह नीचे दी गई है। फ़ाइल में लगभग 22 9, 000 लाइनें और प्रति पंक्ति 202 फ़ील्ड हैं।

public void readThetas(String filename) throws Exception 
{ 
    long t1 = System.currentTimeMillis(); 
    documents = new HashMapX<String,double[]>(); //Document names to indices. 
    Scanner s = new Scanner(new File(filename)); 
    int docIndex = 0; 
    if (s.hasNextLine()) 
     System.out.println(s.nextLine()); // Consume useless first line :) 
    while(s.hasNextLine()) 
    { 
     String[] fields = s.nextLine().split("\\s+"); 
     String docName = fields[1]; 
     numTopics = fields.length/2-1; 
     double[] thetas = new double[numTopics]; 
     for (int i=2;i<numTopics;i=i+2) 
      thetas[Integer.valueOf(fields[i].trim())] = Double.valueOf(fields[i+1].trim()); 
     documents.put(docName,thetas); 
     docIndex++; 
     if (docIndex%10000==0) 
      System.out.print("*"); //progress bar ;) 
    } 
    s.close(); 
    long t2 = System.currentTimeMillis(); 
    System.out.println("\nRead file in "+ (t2-t1) +" ms"); 
} 

ओह !, और HashMapX एक आंतरिक वर्ग इस तरह की घोषणा की है:

public static class HashMapX< K, V> extends HashMap<K,V> { 
    public V get(Object key, V altVal) { 
     if (this.containsKey(key)) 
      return this.get(key); 
     else 
      return altVal; 
    } 
} 
+0

क्या आप कुछ कोड नमूने दिखा सकते हैं? – axtavt

+1

कृपया उन परीक्षणों को पोस्ट करें जो दिखाते हैं कि सीरियलज़ेबल मेमोरी पदचिह्न बढ़ाता है। यदि आप कोड पोस्ट कर सकते हैं जो आपके मानचित्र <स्ट्रिंग, डबल []> का उपयोग कर रहा है तो इससे भी मदद मिलेगी। –

+0

मुझे देखने दो कि क्या मैं वहां आपका बयान समझता हूं। आप कह रहे हैं कि एक धारा Serializable घोषित करके आकार के उदाहरणों पर कब्जा आकार यह क्षणिक से बड़ा है? –

उत्तर

4

तो, मुझे जवाब मिला। यह मेरे कोड में एक स्मृति रिसाव है। Serializable या क्लोनेबल के साथ कुछ भी नहीं था।

यह कोड एक फ़ाइल को पार्स करने का प्रयास कर रहा है। प्रत्येक पंक्ति में मानों का एक सेट होता है जिसे मैं निकालने का प्रयास कर रहा हूं। फिर, मैं उन मानों में से कुछ रखता हूं और उन्हें हैशमैक्स या किसी अन्य संरचना में संग्रहीत करता हूं।

समस्या के मूल यहाँ है:

 String[] fields = s.nextLine().split("\\s+"); 
     String docName = fields[1]; 

और मैं इसे यहाँ का प्रचार:

 documents.put(docName,thetas); 

क्या होता है कि DOCNAME एक सरणी (क्षेत्र) में एक तत्व के लिए एक संदर्भ है और है मैं कार्यक्रम के जीवन के लिए उस संदर्भ को ध्यान में रख रहा हूं (इसे वैश्विक हैश मैप दस्तावेज़ों में संग्रहीत करके)। जब तक मैं उस संदर्भ को जीवित रखता हूं, तब तक पूरे स्ट्रिंग [] फ़ील्ड एकत्रित कचरा नहीं हो सकते हैं। समाधान:

 String docName = new String(fields[1]); // A copy, not a reference. 

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

मुझे आशा है कि यह उन सभी के लिए उपयोगी होगा जो वैश्विक टेक्स्ट में कुछ फ़ील्ड को विभाजित और स्टोर करके बड़ी टेक्स्ट फ़ाइलों को पार्स करते हैं।

सभी को उनकी टिप्पणियों के लिए धन्यवाद। उन्होंने मुझे सही दिशा में निर्देशित किया।

5

यह आपके सभी प्रश्नों के समाधान नहीं सकता है, लेकिन एक तरह से है, जिसमें क्रमबद्धता काफी स्मृति के उपयोग में वृद्धि कर सकते है: http://java.sun.com/javase/technologies/core/basic/serializationFAQ.jsp#OutOfMemoryError

संक्षेप में, यदि आप ObjectOutputStream खोलते हैं तो तब तक कोई भी ऑब्जेक्ट नहीं लिखा जाता है जब तक आप इसे reset() विधि स्पष्ट रूप से कॉल नहीं करते हैं।

+1

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