নাল বনাম ডিসপোজ () নূলে একটি জিনিস সেট করা


108

সিএলআর এবং জিসি যেভাবে কাজ করে আমি মুগ্ধ (আমি সি #, জনের স্কিটির বই / পোস্ট এবং আরও অনেক কিছুর মাধ্যমে সিএলআর পড়ে এই বিষয়ে আমার জ্ঞান প্রসারিত করার জন্য কাজ করছি)।

যাইহোক, বলার মধ্যে পার্থক্য কি:

MyClass myclass = new MyClass();
myclass = null;

অথবা, মাইক্লাসকে আইডিস্পোজেবল এবং ডেস্ট্রাক্টর প্রয়োগ করে এবং ডিসপোজ () কল করে?

এছাড়াও, যদি আমার কাছে একটি স্টেটিং স্টেটমেন্ট (যেমন নীচে) সহ একটি কোড ব্লক থাকে, যদি আমি কোডটি দিয়ে পদক্ষেপ নিই এবং ব্যবহারের ব্লকটি থেকে বেরিয়ে আসি, তখন কি বস্তুটি নিষ্পত্তি হয় বা যখন কোনও আবর্জনা সংগ্রহ ঘটে? আমি যদি কোনওভাবেই ব্লক ব্যবহারে ডিসপোজ () কল করি তবে কী হবে?

using (MyDisposableObj mydispobj = new MyDisposableObj())
{

}

স্ট্রিম ক্লাসগুলির (যেমন বাইনারিওয়াইটার) একটি চূড়ান্তকরণ পদ্ধতি আছে? আমি কেন এটি ব্যবহার করতে চাই?

উত্তর:


210

আবর্জনা সংগ্রহ থেকে নিষ্পত্তি আলাদা করা গুরুত্বপূর্ণ। এগুলি সম্পূর্ণ পৃথক জিনিস, এক পয়েন্টের সাথে সাধারণ যা আমি এক মিনিটে আসব।

Dispose, আবর্জনা সংগ্রহ এবং চূড়ান্তকরণ

আপনি যখন কোনও usingবিবৃতি লিখেন , এটি চেষ্টা / অবশেষে অবরুদ্ধ করার জন্য কেবল সিনট্যাকটিক চিনি হয় যাতে বিবৃতিটির শিরোনামের Disposeকোডটি usingএকটি ব্যতিক্রম ছুঁড়ে মারলেও তাকে বলা হয়। এর অর্থ এই নয় যে অবজেক্টটি ব্লকের শেষে সংগ্রহ করা আবর্জনা।

নিষ্পত্তি হ'ল পরিচালনাহীন সংস্থানসমূহ ( স্মৃতিবিহীন সংস্থানসমূহ) সম্পর্কে। এগুলি ইউআই হ্যান্ডলগুলি, নেটওয়ার্ক সংযোগগুলি, ফাইল হ্যান্ডলগুলি ইত্যাদি হতে পারে এগুলি সীমিত সংস্থানসমূহ, সুতরাং আপনি সাধারণত যত তাড়াতাড়ি সম্ভব এগুলি মুক্তি দিতে চান। IDisposableযখনই আপনার টাইপটি নিয়ন্ত্রণহীন সংস্থানটি "মালিকানাধীন" হয় সরাসরি প্রয়োগ করা উচিত (সাধারণত একটি মাধ্যমে IntPtr) বা অপ্রত্যক্ষভাবে (যেমন একটি Stream, একটি SqlConnectionইত্যাদির মাধ্যমে )।

জঞ্জাল সংগ্রহ কেবল মেমরি সম্পর্কে - একটি সামান্য মোচড় দিয়ে। আবর্জনা সংগ্রহকারী এমন সামগ্রী খুঁজে পেতে সক্ষম হন যা আর উল্লেখ করা যায় না এবং সেগুলি মুক্ত করে। এটি সর্বদা আবর্জনার সন্ধান করে না - কেবলমাত্র যখন এটি সনাক্ত করে যে এটির প্রয়োজন রয়েছে (উদাহরণস্বরূপ যদি স্তূপের একটি "প্রজন্ম" স্মৃতিশক্তি থেকে সরে যায়)।

সুতা হয় চূড়ান্ত । আবর্জনা সংগ্রহকারী এমন অবজেক্টের একটি তালিকা রাখে যা আর অ্যাক্সেসযোগ্য নয়, তবে যার একটি ফাইনালাইজার রয়েছে ( ~Foo()সি # তে লেখা আছে , কিছুটা বিভ্রান্তিকরভাবে - সেগুলি সি ++ ধ্বংসকারীদের মতো কিছুই নয়)। এটি এই বিষয়গুলিতে চূড়ান্তকরণকারীদের চালায়, কেবল যদি তাদের স্মৃতিশক্তি মুক্ত হওয়ার আগে তাদের অতিরিক্ত ক্লিনআপ করার প্রয়োজন হয়।

ফাইনালাইজারগুলি প্রায়শই সর্বদা সম্পদ পরিষ্কার করতে ব্যবহৃত হয় যেখানে প্রকারের ব্যবহারকারী এটি সুশৃঙ্খলভাবে নিষ্পত্তি করতে ভুলে গেছে। সুতরাং আপনি যদি কিছু খুলেন FileStreamতবে কল করতে ভুলে যান Disposeবা Close, ফাইনালাইজারটি শেষ পর্যন্ত আপনার জন্য অন্তর্নিহিত ফাইল হ্যান্ডেল প্রকাশ করবে। একটি লিখিত প্রোগ্রামে, চূড়ান্তকারীদের আমার মতে প্রায় কখনওই গুলি চালানো উচিত নয়।

একটি ভেরিয়েবল সেট করা হচ্ছে null

ভেরিয়েবল নির্ধারণের জন্য একটি ছোট পয়েন্ট null- আবর্জনা সংগ্রহের প্রয়োজনে এটি কখনই প্রয়োজন হয় না। এটি সদস্যের পরিবর্তনশীল হলে আপনি কখনও কখনও এটি করতে চাইতে পারেন, যদিও আমার অভিজ্ঞতায় এটি কোনও জিনিসের "অংশ" এর পক্ষে আর প্রয়োজন হয় না। যখন এটি স্থানীয় পরিবর্তনশীল হয়, আপনি কখন আবার কোনও উল্লেখ ব্যবহার করতে যাবেন না তা জানতে জেআইটি সাধারণত যথেষ্ট স্মার্ট (রিলিজ মোডে) থাকে। উদাহরণ স্বরূপ:

StringBuilder sb = new StringBuilder();
sb.Append("Foo");
string x = sb.ToString();

// The string and StringBuilder are already eligible
// for garbage collection here!
int y = 10;
DoSomething(y);

// These aren't helping at all!
x = null;
sb = null;

// Assume that x and sb aren't used here

আপনি যখন লুপে থাকবেন তখন এক সময় যেখানে স্থানীয় ভেরিয়েবল সেট করা মূল্যবান হতে পারে এবং nullলুপের কয়েকটি শাখাকে ভেরিয়েবল ব্যবহার করা দরকার তবে আপনি জানেন যে আপনি এমন একটি পর্যায়ে পৌঁছেছেন যা আপনি করেননি। উদাহরণ স্বরূপ:

SomeObject foo = new SomeObject();

for (int i=0; i < 100000; i++)
{
    if (i == 5)
    {
        foo.DoSomething();
        // We're not going to need it again, but the JIT
        // wouldn't spot that
        foo = null;
    }
    else
    {
        // Some other code 
    }
}

আইডিস্পোজেবল / ফাইনালাইজারগুলি কার্যকর করা

সুতরাং, আপনার নিজের ধরণের চূড়ান্তকরণগুলি প্রয়োগ করা উচিত? প্রায় অবশ্যই না। যদি আপনি কেবল অপ্রত্যক্ষভাবে নিয়ন্ত্রণহীন সংস্থানগুলি ধরে রাখেন (উদাহরণস্বরূপ আপনি FileStreamসদস্যের পরিবর্তনশীল হিসাবে একটি পেয়েছেন ) তবে আপনার নিজের চূড়ান্তর সংযোজন সাহায্য করবে না: আপনার বস্তুটি যখন স্ট্রিমটি আবশ্যক তখন অবশ্যই আবর্জনা সংগ্রহের জন্য উপযুক্ত হবে, সুতরাং আপনি কেবল নির্ভর করতে পারবেন FileStreamএকটি চূড়ান্তকরণকারী (যদি প্রয়োজন হয় - এটি অন্য কোনও কিছুতে উল্লেখ করতে পারে) having আপনি একটি অপরিচালিত রিসোর্স রাখা চান তাহলে "প্রায়" সরাসরি SafeHandleআপনার বন্ধু - এটা সময়ের সাথে সাথে পেতে যাচ্ছে একটি বিট লাগে, তবে এটি আপনাকে করব মানে প্রায় একটি finalizer আবার লিখতে প্রদান করার প্রয়োজন নেই । আপনার যদি কেবল কোনও উত্স (এ IntPtr) এর সত্যিকারের সরাসরি হ্যান্ডেল থাকে তবে আপনার কেবলমাত্র একটি ফাইনালাইজারের প্রয়োজন হবে এবং আপনার দিকে যাওয়ার চেষ্টা করা উচিতSafeHandleযত দ্রুত সম্ভব. (সেখানে দুটি লিঙ্ক রয়েছে - উভয়ই আদর্শভাবে পড়ুন))

জো ডাফির চূড়ান্তকরণকারী এবং আইডিস্পোজেবল (প্রচুর স্মার্ট লোকের সাথে সহ-লিখিত) এর চারপাশে একটি দীর্ঘ নির্দেশিকা রয়েছে যা পাঠযোগ্য । এটি আপনার সচেতন হওয়া উচিত যে আপনি যদি আপনার ক্লাসগুলি সিল করেন তবে এটি জীবনকে অনেক সহজ করে তোলে: যখন আপনার শ্রেণিটি উত্তরাধিকারের জন্য তৈরি করা হয় তখনই Disposeনতুন ভার্চুয়াল Dispose(bool)পদ্ধতি ইত্যাদি কল করতে ওভাররাইড করার ধরণটি প্রাসঙ্গিক।

এটি কিছুটা দৌড়ঝাঁপ হয়েছে, তবে দয়া করে আপনাকে কিছু চাই যেখানে স্পষ্টতা জিজ্ঞাসা করুন :)


পুনরায় "এক সময় যেখানে এটি স্থানীয় ভেরিয়েবলটি নালায় সেট করার উপযুক্ত হতে পারে" - সম্ভবত কিছু কাঁটাবিড়াল "ক্যাপচার" পরিস্থিতিও (একই ভেরিয়েবলের একাধিক ক্যাপচার) - তবে এটি পোস্টটিকে জটিল করার মতো হবে না! +1 টি ...
মার্ক Gravell

@ মার্ক: এটি সত্য - আমি ক্যাপচারড ভেরিয়েবলগুলির কথা ভাবিনি। হুম। হ্যাঁ, আমি মনে করি আমি এটিকে একা রেখে দেব;)
জন স্কিচ

আপনি কি দয়া করে বলতে পারেন যে আপনি উপরের কোড স্নিপেটে "foo = নাল" সেট করলে কী হবে? আমি যতদূর জানি, এই লাইনটি কেবল পরিচালিত হিপগুলিতে foo অবজেক্টের দিকে নির্দেশিত একটি চলকটির মান সাফ করে? সুতরাং প্রশ্ন সেখানে foo আপত্তি কি হবে? আমরা কি এর নিষ্পত্তি কল করা উচিত?
ওডিসিহ

@ ওডিসেহ: যদি বস্তুটি নিষ্পত্তিযোগ্য হয় তবে হ্যাঁ - আপনার এটি নিষ্পত্তি করা উচিত। উত্তরের সেই অংশটি কেবল আবর্জনা সংগ্রহের সাথে সম্পর্কিত ছিল, যা সম্পূর্ণ পৃথক।
জন স্কিটি

1
আমি কিছু আইডিস্পোজযোগ্য উদ্বেগের জন্য একটি ব্যাখ্যা খুঁজছিলাম, তাই আমি "আইডিসপোজযোগ্য স্কিটি" এর জন্য গুগল করেছিলাম এবং এটি পেয়েছি। গ্রেট! : ডি
ম্যাকিয়েজ ওজনিয়াক

22

আপনি যখন কোনও বস্তু নিষ্পত্তি করেন, সংস্থানগুলি মুক্ত হয়। আপনি যখন কোনও ভেরিয়েবলের নাল বরাদ্দ করেন, আপনি কেবল একটি রেফারেন্স পরিবর্তন করছেন।

myclass = null;

আপনি এটি সম্পাদন করার পরে, বস্তু মাইক্লাসটি এখনও বিদ্যমান রয়েছে বলে উল্লেখ করেছে এবং জিসি এটিকে পরিষ্কার করার আশেপাশে না আসা পর্যন্ত অব্যাহত থাকবে। যদি নিষ্পত্তি স্পষ্টভাবে বলা হয়, বা এটি ব্যবহারের ব্লকে রয়েছে, যে কোনও সংস্থান যত তাড়াতাড়ি সম্ভব মুক্তি দেওয়া হবে।


7
এটা তোলে পারে এখনও যে লাইন নির্বাহ পরে উপস্থিত নয় - এটি আবর্জনা হয়েছে সংগৃহীত হতে পারে আগে যে লাইন। জেআইটি স্মার্ট - প্রায় সবসময় অপ্রাসঙ্গিক এর মতো লাইন তৈরি করে।
জন স্কিটি

6
নালায় সেট করার অর্থ এই হতে পারে যে অবজেক্টের হাতে থাকা সংস্থানগুলি কখনই মুক্ত হয় না । জিসি নিষ্পত্তি করে না, এটি কেবলমাত্র চূড়ান্ত করে, সুতরাং যদি বস্তুটি সরাসরি পরিচালনা না করা সংস্থানগুলি ধরে রাখে এবং এর চূড়ান্তকরণকারী নিষ্পত্তি না করে (বা এর কোনও চূড়ান্তকরণ নেই) তবে সেই সংস্থানগুলি ফাঁস হয়ে যাবে। কিছু সচেতন হতে হবে।
লুক

6

দুটি অপারেশনের একে অপরের সাথে তেমন কিছু করার নেই। আপনি যখন নালার জন্য একটি রেফারেন্স সেট করেন, এটি কেবল এটি করে। এটি মোটেই রেফারেন্স করা ক্লাসকে প্রভাবিত করে না। আপনার ভেরিয়েবলটি কেবল ব্যবহৃত বস্তুর দিকে আর নির্দেশ করে না তবে অবজেক্টটি নিজেই অপরিবর্তিত।

আপনি যখন ডিসপোজ () কল করেন তখন এটি নিজেই অবজেক্টে একটি মেথড কল। ডিসপোজ পদ্ধতি যাই করুক না কেন, এখন বস্তুটিতে সম্পন্ন হয়। তবে এটি আপনার সামগ্রীর রেফারেন্সকে প্রভাবিত করে না।

ওভারল্যাপের একমাত্র ক্ষেত্রটি হ'ল যখন কোনও বস্তুর আর কোনও উল্লেখ নেই, অবশেষে এটি আবর্জনা সংগ্রহ করবে। এবং যদি শ্রেণিটি আইডিস্পোজযোগ্য ইন্টারফেসটি প্রয়োগ করে, তবে আবর্জনা সংগ্রহের আগে অবজেক্টটিতে ডিসপোজ () কল করা হবে।

তবে দুটি কারণেই আপনি আপনার রেফারেন্সটি বাতিল করার পরে অবিলম্বে ঘটবে না। প্রথমত, অন্যান্য উল্লেখ থাকতে পারে, সুতরাং এটি আবর্জনা সংগ্রহ করা একেবারেই পাওয়া যাবে না এবং দ্বিতীয়ত, এটিই শেষ প্রসঙ্গ ছিল, সুতরাং এটি এখন আবর্জনা সংগ্রহের জন্য প্রস্তুত, আবর্জনা সংগ্রাহক মোছার সিদ্ধান্ত না দেওয়া পর্যন্ত কিছুই ঘটবে না বস্তু

কোনও বস্তুতে ডিসপোজ () কল করা কোনওভাবেই বস্তুকে "হত্যা" করে না। এটা সাধারণত তাই যে বস্তুর পরিষ্কার করতে ব্যবহার করা হয় করতে নিরাপদে পরে মুছে যাবে, কিন্তু শেষ পর্যন্ত, সেখানে নিষ্পত্তি সম্পর্কে কিছুই ঐন্দ্রজালিক, এটা শুধু একটি বর্গ পদ্ধতি আছে।


আমি মনে করি এই উত্তরটি প্রশংসিত বা "পুনরাবৃত্ত" এর উত্তরের একটি বিশদ।
dance2die
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.