2012-01-27 20 views
13

साल पहले चल रहा था, मैंने फैसला किया कि कभी भी धागे की FreeOnTerminate संपत्ति को अपने विनाश के बारे में सुनिश्चित करने के लिए सच में भरोसा न करें, क्योंकि मैंने आवेदन की समाप्ति पर दो चीजों की खोज की और तर्क दिया:थ्रेड। फ्रीऑनटर्मिनेट: = ट्रू, मेमोरी रिसाव और भूत

  1. यह एक स्मृति रिसाव पैदा करता है, और
  2. कार्यक्रम की समाप्ति के बाद, धागा अभी भी कहीं न कहीं मेरे नोटबुक के कीबोर्ड के नीचे चल रहा है।

मैंने खुद को एक कामकाज से परिचित किया, और इस बार मुझे परेशान नहीं किया। आज रात तक, जब फिर से किसी को (इस मामले में @MartinJames) my answer पर टिप्पणी की है, जिसमें मैं कुछ कोड है कि धागा के समय से पहले समाप्ति के साथ संयोजन में FreeOnTerminate उपयोग नहीं करता है का संदर्भ लें। मैंने आरटीएल कोड में वापस आ गया और महसूस किया कि मैंने गलत धारणाएं की हैं। लेकिन मुझे इसके बारे में बिल्कुल यकीन नहीं है, इसलिए यह सवाल है।

पहले, पुन: पेश करने ऊपर बयान उल्लेख किया है, इस उदाहरण कोड प्रयोग किया जाता है:

unit Unit3; 

interface 

uses 
    Classes, Windows, Messages, Forms; 

type 
    TMyThread = class(TThread) 
    FForm: TForm; 
    procedure Progress; 
    procedure Execute; override; 
    end; 

    TMainForm = class(TForm) 
    procedure FormClick(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    private 
    FThread: TMyThread; 
    end; 

implementation 

{$R *.dfm} 

{ TMyThread } 

procedure TMyThread.Execute; 
begin 
    while not Terminated do 
    begin 
    Synchronize(Progress); 
    Sleep(2000); 
    end; 
end; 

procedure TMyThread.Progress; 
begin 
    FForm.Caption := FForm.Caption + '.'; 
end; 

{ TMainForm } 

procedure TMainForm.FormClick(Sender: TObject); 
begin 
    FThread := TMyThread.Create(True); 
    FThread.FForm := Self; 
    FThread.FreeOnTerminate := True; 
    FThread.Resume; 
end; 

procedure TMainForm.FormDestroy(Sender: TObject); 
begin 
    FThread.Terminate; 
end; 

end. 
अब

(स्थिति ए), अगर आप फार्म पर एक क्लिक के साथ धागा शुरू करते हैं, करेंगे और उसके बाद प्रपत्र बंद कैप्शन बदल गया, 68 बाइट्स की मेमोरी रिसाव है। मुझे लगता है कि ऐसा इसलिए है क्योंकि धागा मुक्त नहीं होता है। दूसरा, कार्यक्रम तुरंत समाप्त हो जाता है, और आईडीई उसी स्थिति में फिर से सामान्य स्थिति में है। यही कारण है कि (स्थिति बी) के विपरीत: जब ऊपर कोड की अंतिम पंक्ति FreeOnTerminate के उपयोग और नहीं बना FThread.Free में बदल जाता है, यह (अधिकतम।) लेता है सामान्य आईडीई राज्य के लिए कार्यक्रम के लापता होने से 2 सेकंड।

स्थिति बी में देरी इस तथ्य से समझाया गया है कि FThread.FreeFThread.WaitFor पर कॉल करता है, जो दोनों मुख्य धागे के संदर्भ में निष्पादित होते हैं। Classes.pas की आगे की जांच में पता चला है कि FreeOnTerminate की वजह से धागे के विनाश कार्यकर्ता धागा के संदर्भ में किया जाता है। यह स्थिति ए पर निम्नलिखित प्रश्नों का कारण बनता है:

  • क्या वास्तव में एक स्मृति रिसाव है? और यदि ऐसा है: क्या यह महत्वपूर्ण है, इसे अनदेखा किया जा सकता है? क्योंकि जब कोई एप्लिकेशन समाप्त हो जाता है, तो क्या विंडोज अपने सभी आरक्षित संसाधनों को वापस नहीं देता है?
  • धागे से क्या होता है? क्या यह वास्तव में मेमोरी में कहीं और चलता है जब तक कि उसका काम नहीं किया जाता है, या नहीं? और: क्या यह स्मृति रिसाव के सबूत के बावजूद मुक्त है?

अस्वीकरण: स्मृति रिसाव का पता लगाने के लिए, मैं प्रोजेक्ट फ़ाइल में पहले के रूप में this very simple unit का उपयोग करता हूं।

+0

मुझे नहीं पता कि क्या आप पहले ही पढ़ चुके हैं, लेकिन मुझे [रेमंड चेन] (http: //blogs.msdn) से बहुत उपयोगी पोस्ट मिलते हैं।com/b/oldnewthing) इस तरह के विषयों के बारे में। इसे [एक उदाहरण के रूप में] लें (http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx) या [दो] (http://blogs.msdn.com/ बी/oldnewthing/संग्रह/2007/05/02/2365433.aspx # 2,375,204)। टिप्पणियों और लिंक की गई पोस्ट को भी देखें। – EMBarbosa

उत्तर

12

वास्तव में, ओएस समाप्त होने पर सभी प्रक्रिया की स्मृति को पुनः प्राप्त करता है, इसलिए यदि 68 बाइट गैर-मुक्त थ्रेड ऑब्जेक्ट को संदर्भित करते हैं, तो ओएस उन बाइट्स को वैसे भी वापस ले जा रहा है। इससे कोई फर्क नहीं पड़ता कि आपने उस बिंदु पर ऑब्जेक्ट को मुक्त कर दिया है या नहीं।

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

+0

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

+0

एक आखिरी बिंदु - आप शट डाउन पर एवी/एस या 216/217 अपवाद बॉक्स प्राप्त कर सकते हैं, लेकिन आपको कोशिश करनी है। ऐसा करने का एक तरीका यह है कि धागे को फॉर्म के क्षेत्रों में सीधे पढ़ने/लिखना है - आरटीएल फॉर्म बंद कर देता है और ExitProcess() तक पहुंचने से पहले फॉर्म मेमोरी को मुक्त करता है, इसलिए ऐसा धागा शटडाउन के दौरान मुक्त स्मृति तक पहुंचने का प्रयास कर सकता है। मैं बस ऐसी चीजें नहीं करता हूं और इसलिए मुझे कोई समस्या नहीं है। –

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