2010-04-13 24 views
6

मुझे SysUtils इकाई को अंतिम रूप देने के बाद अपना कोड निष्पादित करने की आवश्यकता है।रन-टाइम पैकेज के साथ संकलित अनुप्रयोग के लिए यूनिट अंतिमकरण आदेश?

मैं अलग इकाई में मेरे कोड डाला है और डीपीआर-फ़ाइल का उपयोग करता है खंड में पहले यह शामिल है, इस तरह:

project Project1; 

uses 
    MyUnit, // <- my separate unit 
    SysUtils, 
    Classes, 
    SomeOtherUnits; 

procedure Test; 
begin 
    // 
end; 

begin 
    SetProc(Test); 
end. 

MyUnit इस तरह दिखता है:

unit MyUnit; 

interface 

procedure SetProc(AProc: TProcedure); 

implementation 

var 
    Test: TProcedure; 

procedure SetProc(AProc: TProcedure); 
begin 
    Test := AProc; 
end; 

initialization 

finalization 
    Test; 
end. 

ध्यान दें कि MyUnit कोई उपयोग नहीं है।

यह सामान्य विंडोज एक्सई, कोई कंसोल नहीं है, बिना फॉर्म के और डिफ़ॉल्ट रन-टाइम पैकेज के साथ संकलित। MyUnit किसी भी पैकेज का हिस्सा नहीं है (लेकिन मैंने इसे पैकेज से भी उपयोग करने का प्रयास किया है)।

मुझे उम्मीद है कि MyUnit का अंतिमकरण अनुभाग SysUtils के अंतिमकरण अनुभाग के बाद निष्पादित किया जाएगा। डेल्फी की मदद मुझे बताती है।

हालांकि, यह हमेशा ऐसा नहीं होता है।

मेरे पास 2 टेस्ट ऐप्स हैं, जो उपयोग में सूचीबद्ध टेस्ट रूटीन/डीआरपी-फाइल और इकाइयों में कोड द्वारा थोड़ा अलग हैं। हालांकि, MyUnit सभी मामलों में पहले सूचीबद्ध है।

एक आवेदन के रूप में उम्मीद से चलाया जाता है: -> FinalizeUnits -> ... अन्य इकाइयों ... -> SysUtils के अंतिम रूप दिए जाने -> MyUnit के अंतिम रूप दिए जाने - Halt0> ... अन्य इकाइयों ...

लेकिन दूसरा नहीं है। MyUnit का अंतिमकरण SysUtils के अंतिमकरण से पहले लागू किया गया है। वास्तविक कॉल श्रृंखला इस तरह दिखती है: Halt0 -> FinalizeUnits -> ... अन्य इकाइयां ... -> SysUtils का अंतिमकरण (छोड़ दिया गया) -> MyUnit का अंतिमकरण -> ... अन्य इकाइयां ... -> SysUtils का अंतिमकरण (निष्पादित)

दोनों परियोजनाओं में बहुत ही समान सेटिंग्स हैं। मैंने अपने मतभेदों को हटाने/कम करने के लिए बहुत कुछ करने की कोशिश की, लेकिन मुझे अभी भी इस व्यवहार का कोई कारण नहीं दिख रहा है।

मैंने इसे डीबग करने का प्रयास किया है और यह पता चला है कि: ऐसा लगता है कि प्रत्येक इकाई के पास कुछ प्रकार की संदर्भ गणना होती है। और ऐसा लगता है कि InitTable में एक ही इकाई के गुणा संदर्भ शामिल हैं। जब SysUtils के अंतिमकरण खंड को पहली बार बुलाया जाता है - यह संदर्भ काउंटर बदलता है और कुछ भी नहीं करता है। फिर MyUnit का अंतिम रूप निष्पादित किया जाता है। और फिर SysUtils फिर से कहा जाता है, लेकिन इस बार रेफरी गिनती शून्य तक पहुंच और अंतिम रूप दिए जाने अनुभाग निष्पादित होने

Finalization: // SysUtils' finalization 
5003B3F0 55    push ebp   // here and below is some form of stub 
5003B3F1 8BEC    mov ebp,esp 
5003B3F3 33C0    xor eax,eax 
5003B3F5 55    push ebp 
5003B3F6 688EB50350  push $5003b58e 
5003B3FB 64FF30   push dword ptr fs:[eax] 
5003B3FE 648920   mov fs:[eax],esp 
5003B401 FF05DCAD1150  inc dword ptr [$5011addc] // here: some sort of reference counter 
5003B407 0F8573010000  jnz $5003b580  // <- this jump skips execution of finalization for first call 
5003B40D B8CC4D0350  mov eax,$50034dcc // here and below is actual SysUtils' finalization section 
... 

किसी को भी इस मुद्दे पर प्रकाश टुकड़ा कर सकते हैं कर सकते हैं? क्या मैं कुछ भूल रहा हूँ?

उत्तर

1

मैं एक कारण खोजने में सक्षम था और मैं अपने आप को थोड़ा बेवकूफ लग रहा है अब :)

मेरे दूसरे टेस्ट आवेदन DLL, जो RTL.bpl साथ संकलित किया गया था करने के लिए एक स्थिर संदर्भ है (यह रिक्त, संदर्भ के लिए छोड़कर SysUtils और 1 सरल दिनचर्या के लिए)। इसलिए, चूंकि डीएलएल स्थिर रूप से जुड़ा हुआ है, इसलिए इसे पूर्व में किसी भी कोड को चलाने की संभावना से पहले शुरू किया जाता है।

यह है कि:

DLL के सिस्टम -> DLL के SysUtils -> exe के सिस्टम (छोड़ दिया) ->MyUnit -> exe के SysUtils (छोड़ दिया) -> आदि

अंतिमकरण रिवर्स ऑर्डर में हैं, जिससे SysUtils से पहले MyUnit निष्पादन होता है।

समाधान: सभी परियोजनाओं में पहले MyUnit को शामिल करने की आवश्यकता है।

(ओह, मैं कैसे एक समय मशीन समय में वापस यात्रा और किसी को मजबूर करने के लिए OnBeforeMMShutdown घटना जोड़ने के लिए करना चाहते हैं: डी)

0

आप कुछ भी याद नहीं कर रहे हैं। यह वही है जो हो रहा है।

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

क्या कोई विशेष कारण है कि आपकी MyUnit को SysUtils के बाद अंतिम रूप देने की आवश्यकता है?

+0

> कोई विशेष कारण है कि अपने MyUnit SysUtils के बाद अंतिम रूप देने की जरूरत है? हाँ। यह mem-leaking चेक है। – Alex

+0

@Alexander: क्या यह कुछ खास कर रहा है कि आप FullDebugMode में FastMM के साथ नहीं मिल सकते हैं? –

+0

> क्या यह कुछ खास कर रहा है कि आप FullDebugMode में FastMM के साथ नहीं मिल सकते हैं? यह सवाल नहीं है, जिसे मैं पूछ रहा हूं, तो चलो इसे अलग रखें। फास्टएमएम ने मेरे दूसरे ऐप में बिल्कुल उसी कारण से काम नहीं किया: इसे बहुत जल्दी कहा जाता है। – Alex

10

इकाइयों को प्रारंभिकरण के विपरीत क्रम में अंतिम रूप दिया गया है। प्रारंभिकरण का क्रम गैर-चक्रीय द्वारा निर्धारित किया जाता है (यानी पहले से देखी गई इकाई में कभी नहीं उतरता) यूनिट के पोस्ट-ऑर्डर ट्रैवर्सल का उपयोग मुख्य उपयोग खंड (प्रोग्राम या लाइब्रेरी में) से शुरू होता है। SysInit आमतौर पर प्रारंभ करने के लिए पहली इकाई है, उसके बाद सिस्टम।

पैकेजों की गतिशील लोडिंग चीजों को जटिल करती है, क्योंकि मुख्य EXE या DLL मुख्य छवि द्वारा उपयोग की जाने वाली इकाइयों के प्रारंभिकरण के क्रम को निर्दिष्ट करने के लिए मिलता है। इसलिए जब एक पैकेज गतिशील रूप से लोड हो जाता है, तो वह जो भी सोचता है वह प्रारंभिक क्रम होना चाहिए, लेकिन पहले से शुरू की गई इकाइयां छोड़ी जाएंगी; जब पैकेज गतिशील रूप से उतार दिया जाता है, तो यह विपरीत में होता है।

सामान्य नियम:

  • निचले स्तर बातें उच्च स्तर बातों से पहले प्रारंभ किया जाना चाहिए
  • अंतिम रूप देने के प्रारंभ

ये नियम लगभग हमेशा मतलब के विपरीत क्रम में होना चाहिए। उच्च स्तरीय इकाइयों की शुरुआत अक्सर निम्न स्तर की इकाइयों द्वारा प्रदान की जाने वाली सेवाओं पर भरोसा करती है। उदाहरण के लिए, SysUtils के बिना, डेल्फी में कोई अपवाद समर्थन नहीं है। रिवर्स ऑर्डर फाइनलाइजेशन इसी कारण से समझ में आता है: उच्च स्तरीय अंतिमीकरण निम्न-स्तरीय इकाइयों द्वारा प्रदान की जाने वाली सेवाओं पर निर्भर करता है, इसलिए उन्हें निम्न-स्तरीय इकाइयों के अंतिमकरण से पहले चलना चाहिए।

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

+0

सभी संकुल स्थिर हैं और कोई गतिशील लोडिंग नहीं है - यह निश्चित रूप से है। उत्तर के लिए धन्यवाद, लेकिन मुझे इससे डर था :(मुझे उम्मीद थी कि कोई विशिष्ट चीज़ों को देखने के लिए कुछ संकेत दे सकता है, क्योंकि मुझे नहीं पता कि कहां देखना है। मैं कुछ और बार कोशिश करूंगा। .. – Alex

0

मुझे यकीन नहीं है लेकिन अभी भी टर्बो/बोर्लैंड पास्कल प्रसिद्धि का पुराना पुराना ExitProc वैश्विक चर नहीं है? यदि हां, तो यह आपकी समस्या का समाधान कर सकता है।

+0

हां, यह है। दुर्भाग्य से, इस दिनचर्या को ** ** किसी भी अंतिमकरण खंड को कॉल करने से पहले ** कहा जाता है। इसलिए, यह बहुत जल्दी है। एक्ज़िटप्रोसेस ईवेंट भी है, लेकिन इसे प्रक्रिया समाप्त होने से ठीक पहले कहा जाता है - एक तरीका बहुत देर हो चुकी है। (मैं मेमोरी मैनेजर नहीं लिखता - केवल एक फ़िल्टर स्थापित करता हूं; इसलिए मेरे लिए सिस्टम के अंतिम रूप से पहले मेरे कोड को निष्पादित करना महत्वपूर्ण है जब डिफ़ॉल्ट मेमोरी मैनेजर सभी मेमोरी को मुक्त कर सकता है) हेक, मैं इंस्टॉल करने के बारे में सोच रहा हूं सिस्टम के अंतिम रूप पर हुक: (मजाक कर रहा हूं। – Alex

+0

@Alexander: हो सकता है कि * SysUtils * अंतिमकरण पर एक हुक इतना बुरा विचार नहीं है कि आप इसे हल नहीं कर सकते हैं। – dummzeuch