.net - नेट में XPS दस्तावेज़ को खोलने से स्मृति रिसाव होता है




memory memory-leaks (4)

निम्न कोड स्निपेट XPS फ़ाइलों को खोलते समय मेमोरी रिसाव को दिखाता है यदि आप इसे चलाते हैं और कार्य प्रबंधक देखते हैं, तो यह बढ़ेगा और ऐप के बाहर होने तक स्मृति जारी नहीं करेगा।

'****** कंसोल एप्लिकेशन BEGINS

Module Main

    Const DefaultTestFilePath As String = "D:\Test.xps"
    Const DefaultLoopRuns As Integer = 1000

    Public Sub Main(ByVal Args As String())
        Dim PathToTestXps As String = DefaultTestFilePath
        Dim NumberOfLoops As Integer = DefaultLoopRuns

        If (Args.Count >= 1) Then PathToTestXps = Args(0)
        If (Args.Count >= 2) Then NumberOfLoops = CInt(Args(1))

        Console.Clear()
        Console.WriteLine("Start - {0}", GC.GetTotalMemory(True))
        For LoopCount As Integer = 1 To NumberOfLoops

            Console.CursorLeft = 0
            Console.Write("Loop {0:d5}", LoopCount)

            ' The more complex the XPS document and the more loops, the more memory is lost.
            Using XPSItem As New Windows.Xps.Packaging.XpsDocument(PathToTestXps, System.IO.FileAccess.Read)
                Dim FixedDocSequence As Windows.Documents.FixedDocumentSequence

                ' This line leaks a chunk of memory each time, when commented out it does not.
                FixedDocSequence = XPSItem.GetFixedDocumentSequence
            End Using
        Next
        Console.WriteLine()
        GC.Collect() ' This line has no effect, I think the memory that has leaked is unmanaged (C++ XPS internals).
        Console.WriteLine("Complete - {0}", GC.GetTotalMemory(True))

        Console.WriteLine("Loop complete but memory not released, will release when app exits (press a key to exit).")
        Console.ReadKey()

    End Sub

End Module

'****** कंसोल आवेदन ENDS

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

कोड मूल रूप से एक अन्य धागा और वर्ग में था, लेकिन इस पर सरलीकृत किया गया है।

किसी भी मदद काफी सराहना की

रयान


खैर, मैंने इसे पाया। यह रूपरेखा में एक बग है और इसके आसपास काम करने के लिए आप UpdateLayout को कॉल जोड़ते हैं। निदान का उपयोग तय करने के लिए निम्नलिखित में बदला जा सकता है;

        Using XPSItem As New Windows.Xps.Packaging.XpsDocument(PathToTestXps, System.IO.FileAccess.Read)
            Dim FixedDocSequence As Windows.Documents.FixedDocumentSequence
            Dim DocPager As Windows.Documents.DocumentPaginator

            FixedDocSequence = XPSItem.GetFixedDocumentSequence
            DocPager = FixedDocSequence.DocumentPaginator
            DocPager.ComputePageCount()

            ' This is the fix, each page must be laid out otherwise resources are never released.'
            For PageIndex As Integer = 0 To DocPager.PageCount - 1
                DirectCast(DocPager.GetPage(PageIndex).Visual, Windows.Documents.FixedPage).UpdateLayout()
            Next
            FixedDocSequence = Nothing
        End Using

मैं आपको कोई आधिकारिक सलाह नहीं दे सकता, लेकिन मेरे पास कुछ विचार हैं:

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

UpdateLayout जोड़ें समस्या को हल नहीं कर सकता। Http://support.microsoft.com/kb/942443 के अनुसार, "प्रस्तुतीकरण कोरे डाइल फ़ाइल या प्रस्तुतिफ्रेमवर्क.dll फ़ाइल को प्राथमिक अनुप्रयोग डोमेन में पहले से लोड करना" आवश्यक है।


दिलचस्प। समस्या अभी भी .net ढांचा 4.0 में मौजूद है। मेरा कोड क्रूरता से लीक हो रहा था

प्रस्तावित फिक्स - जहां फिक्स्ड डॉक्यूमेंट स्यूवेन्स के निर्माण के तुरंत बाद अपडेट लयआउट को लूप में कहा जाता है, मेरे लिए 400 पेज टेस्ट दस्तावेज़ पर समस्या ठीक नहीं हुई थी।

हालांकि, निम्नलिखित समाधान ने मेरे लिए समस्या को ठीक किया था पिछले फिक्स के अनुसार, मैंने प्रत्येक पृष्ठ के लूप के बाहर GetFixedDocumentSequence () को कॉल स्थानांतरित कर दिया। "प्रयोग" खंड ... निष्पक्ष चेतावनी है कि मुझे अभी भी यकीन नहीं है कि यह सही है लेकिन यह चोट नहीं लगी है। दस्तावेज को बाद में स्क्रीन पर पृष्ठ पूर्वावलोकन उत्पन्न करने के लिए फिर से उपयोग किया जाता है। तो यह चोट लगती नहीं है

DocumentPaginator paginator 
     =  document.GetFixedDocumentSequence().DocumentPaginator;
int numberOfPages = paginator.ComputePageCount();


for (int i = 0; i < NumberOfPages; ++i)
{
    DocumentPage docPage = paginator.GetPage(nPage);
    using (docPage)   // using is *probably* correct.
    {
        //  VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV

        ((FixedPage)(docPage.Visual)).UpdateLayout();

        //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        //  Adding THAT line cured my leak.

        RenderTargetBitmap bitmap = GetXpsPageAsBitmap(docPage, dpi);

        .... etc...
    }

}

हकीकत में, फिक्स लाइन मेरे GetXpsPageAsBitmap routine (स्पष्टता के लिए ओमिटित) के अंदर जाती है, जो पहले से पोस्ट किए गए कोड के समान है।

योगदान देने वाले सभी लोगों का शुक्रिया।







xps