2009-04-23 16 views
7

मेरे कोड में मैं एक छोटी डेटा-स्टोरेज क्लास का उपयोग करता हूं, जो विभिन्न स्थानों पर बनाई गई है। मेमोरी लीक से बचने और चीजों को आसान बनाने के लिए, मैं संदर्भ गिनती उपयोग करना चाहते हैं, तो मैंऑब्जेक्ट्स के लिए संदर्भ-गणना

type TFileInfo = class (TInterfacedObject, IInterface) 

किया था और TFileInfo.Free करने के लिए अपने सभी मैनुअल कॉल हटा दिया। दुर्भाग्यवश डेल्फी ने बहुत मेमोरी लीक की सूचना दी। पर सर्च कर रहे हैं अतः मैं निम्नलिखित प्रश्न का कारण बताते हुए यह काम नहीं करता पाया:

Why aren't descendants of TInterfacedObject garbage collected?

वहाँ प्रस्तुत एक समाधान नहीं है, लेकिन यह मुझे की आवश्यकता है एक कस्टम इंटरफ़ेस IFileInfo लिखने के लिए (कम से कम अगर मैं इसे सही) और इसे कई गेटर्स और सेटर्स प्रदान करें, जिन्हें मैं टालना चाहता हूं।

संपादित मैं जोड़ने चाहिए कि मैं FileInfo बनाने सम्मिलित हैश तालिकाओं के दो विभिन्न प्रकार में वस्तुओं: एक TBucketList से उतरते और एक और एक CodeGear मंच से एक हैश नक्शा कार्यान्वयन है। आंतरिक रूप से वे दोनों उपयोगकर्ता पॉइंटर्स, इसलिए स्थिति अन्य प्रश्न की तरह ही है।

क्या डेल्फी उपयोग संदर्भ-गणना में वस्तुओं को बनाने की कोई अन्य संभावना है?

उत्तर

5

दुर्भाग्य से, डेल्फी संकलक कांग्रेस को/दिसम्बर संदर्भ संख्या केवल जब आप इंटरफेस (अपने मामले कस्टम इंटरफ़ेस IFileInfo में) का उपयोग आवश्यक कोड उत्पन्न करता है। इसके अलावा, यदि इंटरफेस पॉइंटर (या उस मामले के लिए टॉब्जेक्ट) पर डाला जाता है, तो फिर कोई संदर्भ गिनती संभव नहीं है। TList:: - सूचक झूलते शामिल होंगे

var ifi : IFileInfo; 
begin 
    ifi := TFileInfo.Create; 
    list.Add(TFileInfo(ifi)); 
end; 

विधि रिटर्न सूची [1 list.Count] के बाद उदाहरण के लिए, वैश्विक चर सूची assumming।

तो इंटरफेस का उपयोग हैशपैप में नहीं किया जा सकता है जो उन्हें पॉइंटर्स पर रखता है, हैशपैप कार्यान्वयन उन्हें IInterface के रूप में रखना चाहिए।

+0

लेकिन क्या संकलक सही इंक/डीसी उत्पन्न करता है अगर मैं सभी ऑब्जेक्ट्स को हैश मैप में डालता हूं? – jpfollenius

+0

उत्तर अतिरिक्त जानकारी के साथ संपादित – Kcats

+0

यह कोड संकलित नहीं करता है। वस्तुओं को टाइपकास्ट इंटरफेस करना संभव नहीं है। – dummzeuch

2

यह कार्यक्षमता इंटरफेस के लिए आपूर्ति की जाती है लेकिन वस्तुओं के लिए नहीं।

आप इसे की तरह कुछ भी बना सकते हैं, लेकिन आप TObject की संरचना के कुछ ओवरराइड करने के लिए की जरूरत है:

TRefCountObject = class (TObject) 
private 
    FRefCount : Integer; 
public 
    constructor Create; 

    procedure Free; reintroduce; 

    function RefCountedCopy: TRefCountObject; 
end; 


constructor TRefCountObject.Create; 
begin 
    inherited; 
    FRefCount := 1; 
end; 

procedure TRefCountObject.Free; 
begin 
    if self=nil then Exit; 
    Dec(FRefCount); 
    if FRefCount<=0 then 
    Destroy; 
end; 

function TRefCountObject.RefCountedCopy: TRefCountObject; 
begin 
    Inc(FRefCount); 
    Result := self; 
end; 

आप RefCountedCopy अन्य चर करने के लिए वस्तु सौंपने होंगे। लेकिन फिर आपके पास एक refcounted वस्तु है।

इस उपयोग कैसे करें:

var1 := TRefCountObject.Create; // rc = 1 
var2 := var1.RefCountedCopy;  // rc = 2 
var3 := var1.RefCountedCopy;  // rc = 3 
var2.Free;      // rc = 2 
var1.Free;      // rc = 1 
var4 := var3.RefCountedCopy;  // rc = 2 
var3.Free;      // rc = 1 
var4.Free;      // rc = 0 
+0

विस्तृत उत्तर के लिए धन्यवाद! हालांकि मैं इसे पूरी तरह समझ नहीं पा रहा हूं। मुझे अभी भी TRefCountObject.Free सही कॉल करना है? या मैं इसका उपयोग कैसे करूं? – jpfollenius

+0

कुछ उपयोग जानकारी जोड़ा गया। –

+0

तो मुझे अभी भी प्रत्येक ऑब्जेक्ट के लिए कम से कम एक बार कॉल करना सुनिश्चित करना है, है ना? और इससे बचने का कोई तरीका नहीं है? – jpfollenius

0

इस पर एक लंबी व्याख्या है, लेकिन संक्षेप में: TInterfacedObject (और खुद को नि: शुल्क नहीं बुलाएं) से विरासत, पर्याप्त नहीं है, आपको ऑब्जेक्ट-फैक्ट्री-डायनामिक का उपयोग करने के लिए ऑब्जेक्ट्स बनाने और इंटरफ़ेस का उपयोग करने की आवश्यकता है ऑब्जेक्ट्स को हर जगह ऑब्जेक्ट पर, ऑब्जेक्ट-रेफरेंस-वैरिएबल नहीं। (हां, इसका मतलब है कि आप इसे 'पुराने कोड' को बिना देखे स्विच कर सकते हैं)

3

ऑब्जेक्ट संदर्भ और इंटरफ़ेस संदर्भों को मिश्रित न करें।

var 
    Intf: IInterface; 
    Obj: TFileInfo; 

begin 
    // Interface Reference 
    Intf := TFileInfo.Create; // Intf is freed by reference counting, 
          // because it's an interface reference 
    // Object Reference 
    Obj := TFileInfo.Create; 
    Obj.Free; // Free is necessary 

    // Dangerous: Mixing 
    Obj := TFileInfo.Create; 
    Intf := Obj; // Intf takes over ownership and destroys Obj when nil! 
    Intf := nil; // reference is destroyed here, and Obj now points to garbage 
    Obj.Free; // this will crash (AV) as Obj is not nil, but the underlying object 
      // is already destroyed 
end; 
8

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

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

  1. बैरी केली Smart Pointers बारे में एक पोस्ट में लिखा था। यह डेल्फी 200 9 में जेनरिक का उपयोग करता है, लेकिन मुझे पूरा यकीन है कि आप इसे इस्तेमाल करने वाले विशिष्ट संस्करणों के लिए हार्ड कोड कर सकते हैं यदि आप अभी तक 200 9 का उपयोग नहीं कर रहे हैं (यह एक महान रिलीज बीटीडब्ल्यू है)।

  2. डेल्फी के अधिक संस्करणों और कम संशोधन के साथ काम करने वाला एक और तरीका जेनेज़ अटमपुरी मकोवसेक द्वारा value type wrapper है। यह TStringList के लिए लागू एक उदाहरण है, लेकिन आप इसे किसी भी प्रकार के लिए अनुकूलित कर सकते हैं।

  3. तीसरा तरीका इंटरफेस पॉइंटर बनाना है (बैरी के स्मार्ट पॉइंटर के समान, लेकिन इतना स्मार्ट नहीं)। मेरा मानना ​​है कि जेसीएल में एक है, लेकिन मुझे निश्चित रूप से ब्योरा याद नहीं है। असल में यह एक इंटरफेस है जो निर्माण पर एक टॉब्जेक्ट संदर्भ स्वीकार करता है। फिर जब संदर्भ गणना शून्य तक पहुंच जाती है तो यह आपके द्वारा पारित ऑब्जेक्ट पर निःशुल्क कॉल करता है। यह विधि वास्तव में केवल अल्पकालिक उदाहरणों के लिए काम करती है कि आप पैरामीटर के रूप में नहीं गुजर रहे हैं क्योंकि आप वास्तव में उपयोग किए गए संदर्भ से संदर्भ गणना संदर्भ को अलग करते हैं। मैं इसके बजाय अन्य दो तरीकों में से एक की सिफारिश करता हूं, लेकिन यदि आप इस विधि को पसंद करते हैं और अधिक जानकारी चाहते हैं तो मुझे बताएं।

डेल्फी के बारे में यह बात है, चीजों को पूरा करने के एक स्वतंत्र तरीके हैं। विकल्प # 1 मेरी राय में सबसे अच्छा है - डेल्फी 200 प्राप्त करें और यदि आप कर सकते हैं तो उस विधि का उपयोग करें।

शुभकामनाएं!

+0

मैंने आपका प्रश्न फिर से पढ़ा और मुझे नहीं पता कि इनमें से कोई भी उत्तर आपकी सूचियों को स्वीकार करने के बाद से काम करता है ऑब्जेक्ट्स क्योंकि वे पॉइंटर्स का उपयोग करते हैं। ये विधियां या तो इंटरफेस या रिकॉर्ड्स का उपयोग करती हैं। फिर, डेल्फी 200 9 में जाने से जेनेरिक कंटेनर मिलते हैं जो रिकॉर्ड, इंटरफेस, ऑब्जेक्ट्स या देशी प्रकारों के साथ काम करते हैं। –

+0

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

+0

@JimMcKeeth: मैं डेल्फी 200 का उपयोग कर रहा हूं, लेकिन इसमें अभी भी एक सामान्य और उचित रूप से कुशल हैश नक्शा कार्यान्वयन की कमी है, है ना? – jpfollenius

1

क्या पहले से ही कहा गया है करने के लिए जोड़ने के लिए, यदि आप इंटरफेस के लिए संदर्भ संग्रहीत करना चाहते हैं, एक TList उपयोग करने के बजाय, एक TInterfaceList का उपयोग करें। रेफरी गिनती लगातार काम करेगी।

+0

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

3

यदि आप टॉब्जेक्ट उदाहरणों पर निःशुल्क कॉल को खत्म करना चाहते हैं तो आप देशी डेल्फी के लिए कचरा कलेक्टर देखना चाहेंगे। मैं 2 अलग कचरा कलेक्टरों और एक कचरा इकट्ठा करने की तकनीक से अवगत हूं, प्रत्येक पेशेवर और विपक्ष के साथ।

द्वारा Henrick Hellstrom

  • API for Boehm Garbage Collector DLL द्वारा उनमें से एक शायद आपके लिए काम करेगा।

  • +0

    +1 धन्यवाद! मैं उन्हें देख लूंगा। – jpfollenius

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