2010-02-28 10 views
12

मेरा जावा लिखित एप्लिकेशन बहुत अधिक मेमोरी का उपभोग करता है।जावा बहुत अधिक मेमोरी का उपभोग करता है

प्रोग्राम कैसे काम करता है: उपयोगकर्ता कैलेंडर (जीयूआई) से एक तिथि चुनता है और एप्लिकेशन डेटा को जेटीबल घटक में लोड करता है। हर बार डेटा लोड किया जाता है, नया टेबल मॉडल बनाया और सेट किया जाता है। कोई नया जेटीबल नहीं बनाया गया है, सिर्फ मॉडल।

समस्या क्या है?: कैलेंडर से प्रत्येक नए दिन का चयन और जेटीबल में लोडिंग मेमोरी की 2-3 एमबी का उपभोग करता है। प्रारंभिक ऐप पर सीसीए 50-60 एमबी रैम का उपभोग करता है, कैलेंडर पर कुछ "क्लिक" (20 की तरह) के बाद, आवेदन पूर्ण हीप आकार (128 एमबी) का उपभोग करता है। आवेदन दुर्घटनाओं, निश्चित रूप से ...

मुझे क्या करना चाहिए?: मुझे यकीन है कि डेटाबेस क्वेरी ठीक है। मैं किसी भी तरह से बड़े ढेर आकार को सेट कर सकता हूं (मैं googled, लेकिन यह मेरे कंप्यूटर के लिए केवल समाधान होगा, उपयोगकर्ता यह नहीं करेंगे) या मुझे किसी भी तरह डीबी डेटा के साथ पुराने tableModel हटा देना चाहिए। लेकिन क्या यह कचरा कलेक्टर का काम नहीं होना चाहिए? मैं इसे मजबूर करने में सक्षम हूं (System.gc()) लेकिन इससे मदद नहीं मिलती है ...

किसी भी सलाह के लिए धन्यवाद!

संपादित करें: कोड कैलेंडर की घटनाओं से निपटने के लिए (मैं हटाए गए जावाडोक, यह मेरी मातृभाषा में है)

package timesheet.handlers; 

import java.util.Calendar; 
import java.util.Date; 
import java.util.GregorianCalendar; 
import java.util.List; 
import org.jdesktop.swingx.JXMonthView; 
import org.jdesktop.swingx.event.DateSelectionEvent; 
import org.jdesktop.swingx.event.DateSelectionListener; 
import timesheet.database.WorkerOperations; 
import timesheet.frames.WorkerFrame; 
import timesheet.logictrier.*; 


public class WorkerMonthViewHandler { 
    private JXMonthView monthView; 
    private WorkerFrame workerFrame; 
    private WorkerOperations wops; 
    private Date[] week = new Date[5]; 
    private WorkerTasksTableHandler wtth; 

    public WorkerMonthViewHandler(WorkerFrame workerFrame) { 
     this.workerFrame = workerFrame; 
     this.monthView = workerFrame.getWorkerMonthView(); 
     wops = workerFrame.getWorkerOperations(); // for DB usage 
    } 

    public void initMonthView() { 
     List<Task> tasks = wops.getWorkerTasks(workerFrame.getWorker()); // db select 
     for (Task task : tasks) { 
      if (!monthView.getSelection().contains(task.getPlannedStart())) { 
       monthView.addFlaggedDates(task.getPlannedStart()); 
       monthView.addFlaggedDates(task.gePlannedEnd()); // not really important 
      } 
     } 
     monthView.setSelectionDate(new Date()); 
     monthView.getSelectionModel().addDateSelectionListener(new DateSelectionListener() { 
      public void valueChanged(DateSelectionEvent dse) { 
       Date d = monthView.getSelectionDate(); 
       for (int i=0; i<week.length; i++) { 
        if (d.equals(week[i])) {  
         return; 
        } 
       } 
       Calendar cal = new GregorianCalendar(); 
       cal.setTime(d); 
       long dayMs = 24 * 60 * 60 * 1000; 
       switch (cal.get(Calendar.DAY_OF_WEEK)) { 
        case(Calendar.MONDAY) : { 
         week[0] = new Date(cal.getTimeInMillis()); 
         week[1] = new Date(cal.getTimeInMillis()+dayMs); 
         week[2] = new Date(cal.getTimeInMillis()+2*dayMs); 
         week[3] = new Date(cal.getTimeInMillis()+3*dayMs); 
         week[4] = new Date(cal.getTimeInMillis()+4*dayMs); 
        } break; 
        case (Calendar.TUESDAY) : { 
         week[0] = new Date(cal.getTimeInMillis()-dayMs); 
         week[1] = new Date(cal.getTimeInMillis()); 
         week[2] = new Date(cal.getTimeInMillis()+1*dayMs); 
         week[3] = new Date(cal.getTimeInMillis()+2*dayMs); 
         week[4] = new Date(cal.getTimeInMillis()+3*dayMs); 
        } break; 
        case (Calendar.WEDNESDAY) : { 
         week[0] = new Date(cal.getTimeInMillis()-2*dayMs); 
         week[1] = new Date(cal.getTimeInMillis()-dayMs); 
         week[2] = new Date(cal.getTimeInMillis()); 
         week[3] = new Date(cal.getTimeInMillis()+1*dayMs); 
         week[4] = new Date(cal.getTimeInMillis()+2*dayMs); 
        } break; 
        case (Calendar.THURSDAY) : { 
         week[0] = new Date(cal.getTimeInMillis()-3*dayMs); 
         week[1] = new Date(cal.getTimeInMillis()-2*dayMs); 
         week[2] = new Date(cal.getTimeInMillis()-1*dayMs); 
         week[3] = new Date(cal.getTimeInMillis()); 
         week[4] = new Date(cal.getTimeInMillis()+1*dayMs); 
        } break; 
        case (Calendar.FRIDAY) : { 
         week[0] = new Date(cal.getTimeInMillis()-4*dayMs); 
         week[1] = new Date(cal.getTimeInMillis()-3*dayMs); 
         week[2] = new Date(cal.getTimeInMillis()-2*dayMs); 
         week[3] = new Date(cal.getTimeInMillis()-dayMs); 
         week[4] = new Date(cal.getTimeInMillis()); 
        } break; 
        case (Calendar.SATURDAY) : { 
         week[0] = new Date(cal.getTimeInMillis()-5*dayMs); 
         week[1] = new Date(cal.getTimeInMillis()-4*dayMs); 
         week[2] = new Date(cal.getTimeInMillis()-3*dayMs); 
         week[3] = new Date(cal.getTimeInMillis()-2*dayMs); 
         week[4] = new Date(cal.getTimeInMillis()-dayMs); 
        } break; 
        case (Calendar.SUNDAY) : { 
         week[0] = new Date(cal.getTimeInMillis()-6*dayMs); 
         week[1] = new Date(cal.getTimeInMillis()-5*dayMs); 
         week[2] = new Date(cal.getTimeInMillis()-4*dayMs); 
         week[3] = new Date(cal.getTimeInMillis()-3*dayMs); 
         week[4] = new Date(cal.getTimeInMillis()-2*dayMs); 
        } break; 
       } 
       wtth = new WorkerTasksTableHandler(workerFrame,week); 
       wtth.createTable(); // sets model on JTable 
      } 
     }); 
    } 

    public void reportTask() { 
     wtth.reportTasks(); // simple DB insert 
    } 
} 

का उपयोग NetBeans प्रोफाइलर: लेने की तिथि: सूर्य 28 14:25:16 सीईटी फ़रवरी 2010 फ़ाइल: सी: ... \ निजी \ प्रोफाइलर \ java_pid4708.hprof फ़ाइल का आकार: 72,2 एमबी

Total bytes: 62 323 264 
Total classes: 3 304 
Total instances: 1 344 586 
Classloaders: 18 
GC roots: 2 860 
Number of objects pending for finalization: 0 
+1

हम कोड देख सकते हैं? – Fernando

+1

आप एक डीबी का जिक्र करते हैं ... क्या आप यह कर सकते हैं कि क्या कर रहा है, आप क्या डीबी का उपयोग कर रहे हैं, अगर आप अपने परिणामसेट्स बंद कर रहे हैं, आदि ... एक बहुत अधिक संभावित अपराधी लगता है। साथ ही, क्या आप पुराने मॉडल के लिए कोई संदर्भ रखते हैं? मॉडल में आप कितना डेटा लोड करते हैं? क्या आपकी तालिका में कस्टम रेंडरर हैं? – PSpeed

+0

नोट: अतीत में मैंने जेटीबल टेबल मॉडल को बदल दिया है जिसमें कई हजार पंक्तियां हैं ... और डिफ़ॉल्ट रूप से हीप आकार में कभी वृद्धि नहीं हुई है। तो यहां कुछ और खेलना है। – PSpeed

उत्तर

8

आप इस के खिलाफ YourKit की तरह एक प्रोफाइलर चलाने है ? मुझे संदेह है कि रिलीज होने पर संदर्भों के कारण यह कुछ स्मृति रिसाव दिखाएगा। ध्यान दें कि System.gc() एक संकेत जेवीएम में है, और जीसी चक्र को मजबूर नहीं करता है।

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

java -Xmx256m {classname} 

आदि यह देखने के लिए कि क्या यह समस्या को स्थायी रूप से हल करता है या नहीं। यदि ऐसा नहीं होता है, तो यह एक स्मृति रिसाव को इंगित करता है।

+0

मैं आपकेकिट, थेंक्स – Miso

+0

के बारे में पढ़ने जा रहा हूं, यह बहुत बुरा है :-( – Miso

+4

जेडीके_1.6.10 – crowne

0

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

+0

नीचे पोस्ट किया गया है, ठीक है मेरे पास दिनांक चयन चयनकर्ता हर समय दिनांक बदल गया है, नया टेबलमोल बनाया गया है (श्रोता यह करता है, और डीबी से डेटा भी लोड करता है) – Miso

+0

उन हैंडलर में क्या चल रहा है, इस पर बहुत सावधानी से देखो उन्हें। यदि किसी हैंडलर में कोई संदर्भ आयोजित किया जाता है और हैंडलर संवाद बॉक्स द्वारा आयोजित किया जाता है, तो वह स्मृति मुक्त नहीं होगी। यह जीसी भाषाओं का उपयोग करने का नकारात्मक हिस्सा है, आप केवल पॉइंटर को हटा नहीं सकते हैं और देख सकते हैं कि नल पॉइंटर अपवाद कहां पॉप अप करता है। – Blindy

+0

मैंने कुछ कोड जोड़ा, कृपया एक नज़र डालें, शायद आपको कुछ त्रुटि – Miso

2

Veijko Krunic के महान पेपर How to Fix Memory Leaks in Java पढ़ें। वह इसी तरह की समस्याओं के लिए एक निदान पथ का सुझाव देता है।

0

आपको हर बार मिलीसेकंद सटीकता की तारीखों की आवश्यकता नहीं है। ऐसा लगता है कि सप्ताह का एक ही दिन पर्याप्त है।

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

प्रत्येक बार "नया" कैलेंडर की आवश्यकता नहीं है, या तो। मैं इसे इस तरह से करूँगा:

Calendar cal = Calendar.getInstance(); 

कारखाने को इसे बाहर निकालने दें।

मैं समय के लिए जोडा जैसे पुस्तकालय को देखने की भी सिफारिश करता हूं। आप यहां क्या कर रहे हैं उससे अधिक कुशल होना निश्चित है।

अद्यतन: शायद this आपकी मेमोरी लीक को फेरेट करने में आपकी मदद कर सकता है। कम से कम यह देखने के लिए कहां से एक चेकलिस्ट है।

+0

दिखाई देगी, जिसका मतलब है कि क्लास एट्रिब्यूट बनाना और इसे कन्स्ट्रक्टर में घोषित करना है? – Miso

+0

ऊपर संपादित देखें। – duffymo

2

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

monthView.getSelectionModel().addDateSelectionListener(new DateSelectionListener() { 
    ... 
} 

नई DateSelectionListener आपके द्वारा बनाए गए इस (WorkerMonthViewHandler) के लिए एक संदर्भ है, मैं बिल्कुल नहीं देख सकता कि कैसे initMonthView का उपयोग किया जाता है, इस बारे में और जानने के बिना कोई समस्या क्यों उत्पन्न होगी, लेकिन मुझे अज्ञात आंतरिक वर्गों को दोबारा मिल गया है क्योंकि स्विंग ऑब्जेक्ट्स पर श्रोताओं ने पहचान की है और अंत में कई स्मृति लीक को हल करने में मदद की है । श्रोताओं को तब तक अस्तित्व में रहेगा जब तक वे स्विंग ऑब्जेक्ट को सुन रहे हों, इसलिए एक नया वर्कर मॉन्थव्यूहैंडलर बनाने के बाद भी आसपास लटका होगा, मूल स्विंग जेटीबल अभी भी वही है।

यदि आप इस पर प्रयास करने के लिए कुछ और पढ़ना चाहते हैं, तो http://www.javalobby.org/java/forums/t19468.html

उम्मीद है कि इससे मदद मिलती है।

+0

अगर मैं सही ढंग से समझता हूं, तो मुझे डेटसेलेक्शन लिस्टर (एफ.ई. कन्स्ट्रक्टर में) का केवल एक उदाहरण बनाना चाहिए? आप शायद सही हैं, हालांकि मुझे 99% यकीन है कि स्विंग – Miso

+0

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

+1

@ मिसो, वास्तव में नहीं ... असली मुद्दा यह है कि यदि आप श्रोताओं को और अधिक जोड़ते हैं तो आपको उन्हें फिर से हटाने की भी आवश्यकता है। स्विंग-आधारित अनुप्रयोगों में मिली मेमोरी लीक का सबसे बड़ा स्रोत कोड है जो अपने श्रोताओं को साफ करने के लिए भूल जाता है। बेनामी आंतरिक वर्ग समस्या को बढ़ाते हैं क्योंकि वे अपने बाहरी उदाहरणों के संदर्भ रखते हैं। – PSpeed

0

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

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

+0

तो मैं की जांच कर रहा हूं तस्वीर पर एक नज़र डालें, मैं सेल पर एक पागल आदमी की तरह क्लिक कर रहा था जिसमें सेलएडिटर है मेरे कस्टम स्पिनर एडिटर के रूप में सेट करें (दूसरे शब्दों में, जेएसपीनर को संभालने के लिए सेल पर डबल क्लिक करें) .... प्रयुक्त/आवंटित ढेर को देखें, वास्तव में यह केवल उगता है .... http://i49.tinypic.com /160wx0g.jpg – Miso

+1

ठीक है, जो कि और भी सबूत है कि कुछ वस्तुओं को अभी जारी नहीं किया जा रहा है। (यह मेरे साथ पहले हुआ है जब मेरे पास बाहर से हैश मैप में एक संवाद का संदर्भ था, इसलिए जब मैंने संवाद का निपटारा किया, तब भी इसका एक संदर्भ था और जावा जीसी नहीं करेगा।) कुछ ऐसा इस्तेमाल करें YourKit या JProfiler और दो अलग-अलग ढेर डंप पर एक अंतर करें। (जेपीरोफेलर आपको बताएगा कि ढेर के बीच कौन सा ऑब्जेक्ट नया है, इसलिए आप उन उदाहरणों को तुरंत अनदेखा कर सकते हैं जो आप जो कर रहे हैं उसके बजाए एप्लिकेशन का हिस्सा हैं।) –

0

कोड से बताना मुश्किल है, लेकिन किसी भी मौके पर आप फ्लैगडडेट्स को लगातार जोड़ रहे हैं?

public void initMonthView() { 
    List<Task> tasks = wops.getWorkerTasks(workerFrame.getWorker()); // db select 
    for (Task task : tasks) { 
     if (!monthView.getSelection().contains(task.getPlannedStart())) { 
      monthView.addFlaggedDates(task.getPlannedStart()); 
      monthView.addFlaggedDates(task.gePlannedEnd()); // not really important 
     } 
    } 
+0

नहीं, केवल पहली बार JXmonthView प्रारंभ किया गया है (और RESET JButton पर भी), तो अक्सर नहीं :) – Miso

-1

सज्जनो, उत्तर के लिए सभी को धन्यवाद। मैं प्रत्येक प्रतिक्रिया की सराहना करता हूं।

मैंने अपना खुद का और अधिक दृश्यमान होने के लिए जोड़ा, वास्तव में एक सही नहीं चुन सकता।

तो जब आप कोड मैं मूल प्रश्न में तैनात करने के लिए और अधिक ध्यान से देखो, तो आप इन दो पंक्तियों

 wtth = new WorkerTasksTableHandler(workerFrame,week); 
     wtth.createTable(); // sets model on JTable 

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

तस्वीर के लिए एक नजर डालें, अब यह बहुत कम रैम की खपत और जीसी वास्तव में काम करता है :) alt text http://img694.imageshack.us/img694/1604/gcworks.jpg

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