2015-09-17 10 views
5

मेरे पास ऐसी स्थिति है जो महीनों के लिए मुझे यातना दे रही है: मैं ओओएम अपवाद (हीप स्पेस) प्राप्त कर रहा हूं और ढेर डंप का निरीक्षण करने पर मुझे ऑब्जेक्ट्स के लाखों उदाहरण मिल गए हैं जिन्हें मैंने कभी आवंटित नहीं किया था, लेकिन संभवतः अंतर्निहित पुस्तकालयों में आवंटित किया गया था। ज्यादा खून, पसीने और आँसू बाद मैं स्मृति रिसाव पैदा कोड स्थानीय बनाना करने में कामयाब रहे है और मैं इसे स्पष्ट करने के लिए एक, कम से कम पूरा और निरीक्षण कोड नमूना बना दिया है:जावा एक्सपैथ मेमोरी रिसाव?

:

import java.util.logging.Level; 
import java.util.logging.Logger; 
import javafx.application.Application; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.concurrent.Worker; 
import javafx.scene.web.WebEngine; 
import javafx.stage.Stage; 
import javax.xml.xpath.XPath; 
import javax.xml.xpath.XPathConstants; 
import javax.xml.xpath.XPathExpressionException; 
import javax.xml.xpath.XPathFactory; 
import org.w3c.dom.Node; 
import org.w3c.dom.NodeList; 

public class MVC extends Application implements ChangeListener<Worker.State>{ 

    private final WebEngine engine = new WebEngine(); 
    private final String url = "https://biblio.ugent.be/publication?sort=publicationstatus.desc&sort=year.desc&limit=250&start=197000"; 
    private final XPath x = XPathFactory.newInstance().newXPath(); 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     System.setProperty("jsse.enableSNIExtension", "false"); 
     engine.getLoadWorker().stateProperty().addListener(this); 
     engine.load(url); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

    private NodeList eval(Node context, String xpath) throws XPathExpressionException{ 
     return (NodeList)x.evaluate(xpath, context, XPathConstants.NODESET); 
    } 

    @Override 
    public void changed(ObservableValue<? extends Worker.State> observable, Worker.State oldValue, Worker.State newValue) { 
     if (newValue==Worker.State.SUCCEEDED) { 
      try { 
       while(true){ 
        NodeList eval = eval(engine.getDocument(), "//span[@class='title']"); 
        int s = eval.getLength(); 
       } 
      } catch (XPathExpressionException ex) { 
       Logger.getLogger(MVC.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
    } 
} 

कोड निम्नलिखित करता है

  • JavaFXWebEngine का उपयोग कर एक दस्तावेज़ लोड करें।
  • बेहद परिणाम या यह की ओर इशारा संग्रह किए बिना javax.xml संकुल, का उपयोग कर दस्तावेज़ पर एक xpath क्वेरी प्रदर्शन करते हैं।

चलाने के लिए, जावाएफएक्स एप्लिकेशन बनाएं, डिफ़ॉल्ट पैकेज में MVC.java नाम की एक फ़ाइल जोड़ें, कोड दर्ज करें और हिट रन करें। कोई भी प्रोफाइलिंग टूल (मैं VisualVM का उपयोग करता हूं) आपको तुरंत दिखाता है कि कुछ मिनटों में, ढेर अनियंत्रित रूप से बढ़ता है। निम्नलिखित वस्तुओं आवंटित किया जाना है, लेकिन कभी जारी नहीं लग रहे हैं:

  • java.util.HashMap$Node
  • com.sun.webkit.Disposer$WeakDisposerRecord
  • com.sun.webkit.dom.NamedNodeMapImpl$SelfDisposer
  • java.util.concurrent.LinkedBlockingQueue$Node

यह व्यवहार यूआरएल की, हर बार जब मैं कोड को चलाने के लिए होता परवाह किए बिना मैं लोड या xpath मैं दस्तावेज़ पर निष्पादित करता हूं।

सेटअप जिसके साथ मैं परीक्षण किया:

  • MBP चल OS X Yosemite (अप-टू-डेट)
  • JDK 1.8.0_60

किसी को भी इस समस्या को पुनः कर सकते हैं? क्या यह एक वास्तविक स्मृति रिसाव है? क्या मै कुछ कर सकता हुं?

संपादित

मेरा एक सहयोगी JDK 1.8.0_45 के साथ एक W7 मशीन पर समस्या reproduced, और यह रूप में अच्छी तरह एक Ubuntu सर्वर पर होता है।

संपादित 2

मैं javax.xml पैकेज के लिए एक विकल्प के रूप में jaxen परीक्षण किया है, लेकिन परिणाम एक ही है, जो मुझे विश्वास करने के लिए बग सूरज वेबकिट भीतर गहरे झूठ हैं

+0

संभवतः संबंधित: http://stackoverflow.com/questions/6340802/java-xpath-apache-jaxp-implementation-performance – Warkst

+2

मैं इस पर पुन: पेश कर सकते हैं विंडोज 7 64-बिट, जावा 1.8.0_60। यह एक स्मृति रिसाव प्रतीत होता है। मैंने JavaFX को शामिल किए बिना एक मनमानी एक्सएमएल फ़ाइल पर एक ही लूप करने की कोशिश की, और एक ही परिणाम मिला। – VGR

+0

इस पर ध्यान देने के लिए धन्यवाद! मैंने javafx का उपयोग नहीं करने पर भी विचार नहीं किया था, लेकिन आप पूरी तरह से सही हैं, बग गहरी है, और जिस तरह से डब्ल्यू 3 सी दस्तावेज प्रदान किया गया है वह महत्वपूर्ण नहीं है। – Warkst

उत्तर

7

मैंने उबंटू में भी jdk1.8.60 के साथ रिसाव का पुनरुत्पादन किया। मैंने काफी कुछ प्रोफाइलिंग और डिबगिंग किया और मूल कारण सरल है और इसे आसानी से ठीक किया जा सकता है। XPath सामान में कोई स्मृति रिसाव नहीं है।

एक वर्ग com.sun.webkit.Disposer है, जो XPath मूल्यांकन के दौरान बनाए गए कुछ आंतरिक संरचनाओं की निरंतर सफाई कर रहा है।डिस्पोजेर इंटर्नली Invoker.getInvoker() के माध्यम से क्लीनअप को कॉल करता है। InvokeOnEventThread (यह);। यदि आप कोड को संकुचित करते हैं तो आप इसे देख सकते हैं। विभिन्न धागे का उपयोग करके, इनवॉकर के विभिन्न कार्यान्वयन होते हैं। यदि आप जावाएफएक्स के भीतर काम करते हैं, तो Invoker JavaFX थ्रेड में समय-समय पर सफाई करता है।

हालांकि, बदल गया श्रोता विधि जावाएफएक्स थ्रेड में भी बुलाया जाता है, और यह कभी वापस नहीं आता है, इसलिए सफाई के पास कभी भी ऐसा मौका नहीं होता है।

मैंने आपके कोड को संशोधित किया है, ताकि बदल दिया विधि केवल एक नया धागा उत्पन्न करती है और लौटाती है, और प्रसंस्करण असीमित रूप से किया जाता है। और लगता है क्या - स्मृति किसी भी अधिक नहीं बढ़ता है:

@Override 
public void changed(ObservableValue<? extends Worker.State> observable, Worker.State oldValue, Worker.State newValue) { 
    if (newValue==Worker.State.SUCCEEDED) { 
     new Thread(() ->{ 
      try { 
       while(true){ 
        NodeList eval = eval(engine.getDocument(), "//span[@class='title']"); 
        int s = eval.getLength(); 
       } 
      } catch (XPathExpressionException ex) { 
       Logger.getLogger(MVC.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     }).start(); 
    } 
} 
+0

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

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