আমি এখানে যে তথ্য দিচ্ছি তা নতুন নয়, আমি এটি সম্পূর্ণতার জন্য যুক্ত করেছি।
এই কোডটির ধারণাটি বেশ সহজ:
- অবজেক্টগুলির একটি অনন্য আইডি প্রয়োজন, যা ডিফল্টরূপে সেখানে নেই। পরিবর্তে, আমাদের পরবর্তী সেরা জিনিসের উপর নির্ভর
RuntimeHelpers.GetHashCode
করতে হবে , যা আমাদের এক ধরণের অনন্য আইডি পেতে
- স্বতন্ত্রতা পরীক্ষা করতে, এটি আমাদের ব্যবহার করা দরকার বোঝায়
object.ReferenceEquals
- তবে, আমরা এখনও একটি অনন্য আইডি রাখতে চাই, তাই আমি একটি যুক্ত করেছি
GUID
, এটি সংজ্ঞা অনুসারে অনন্য unique
- কারণ আমার যদি কিছু না থাকে তবে আমি লক করা পছন্দ করি না, আমি ব্যবহার করি না
ConditionalWeakTable
।
সংযুক্ত, এটি আপনাকে নিম্নলিখিত কোডটি দেবে:
public class UniqueIdMapper
{
private class ObjectEqualityComparer : IEqualityComparer<object>
{
public bool Equals(object x, object y)
{
return object.ReferenceEquals(x, y);
}
public int GetHashCode(object obj)
{
return RuntimeHelpers.GetHashCode(obj);
}
}
private Dictionary<object, Guid> dict = new Dictionary<object, Guid>(new ObjectEqualityComparer());
public Guid GetUniqueId(object o)
{
Guid id;
if (!dict.TryGetValue(o, out id))
{
id = Guid.NewGuid();
dict.Add(o, id);
}
return id;
}
}
এটি ব্যবহার করতে, এর একটি উদাহরণ তৈরি করুন UniqueIdMapper
এবং জিইউইডি ব্যবহার করুন এটি বস্তুর জন্য ফিরে আসে।
অভিযোজ্য বস্তু
সুতরাং, এখানে আরও কিছু চলছে; আমাকে একটু লিখতে দিন ConditionalWeakTable
।
ConditionalWeakTable
কয়েকটা জিনিস করে সর্বাধিক গুরুত্বপূর্ণ বিষয়টি হ'ল আবর্জনা সংগ্রহকারী সম্পর্কে এটি যত্নশীল নয়, এটি হ'ল: আপনি এই টেবিলটিতে যে বিষয়গুলি উল্লেখ করেছেন তা নির্বিশেষে সংগ্রহ করা হবে। আপনি যদি কোনও বস্তুর সন্ধান করেন তবে এটি মূলত উপরের অভিধানের মতোই কাজ করে।
কৌতুহল না? সর্বোপরি, যখন কোনও বস্তু জিসি দ্বারা সংগ্রহ করা হচ্ছে, তখন এটি অনুসন্ধান করে যে কোনও বস্তুর উল্লেখ রয়েছে কিনা, এবং যদি সেখানে থাকে তবে তা সেগুলি সংগ্রহ করে। সুতরাং যদি কোন বিষয় আছেConditionalWeakTable
, তবে কেন রেফারেন্সযুক্ত বস্তুটি সংগ্রহ করা হবে?
ConditionalWeakTable
একটি ছোট ট্রিক ব্যবহার করে, যা কিছু অন্যান্য। নেট স্ট্রাকচারগুলিও ব্যবহার করে: বস্তুর রেফারেন্স সংরক্ষণ করার পরিবর্তে এটি আসলে একটি ইন্টারপিটার সঞ্চয় করে। যেহেতু এটি আসল তথ্যসূত্র নয়, অবজেক্টটি সংগ্রহ করা যায়।
সুতরাং, এই সময়ে 2 টি সমস্যা সমাধান করতে হবে address প্রথমত, অবধি বস্তুগুলি গাদা হয়ে স্থানান্তরিত করা যায়, সুতরাং আমরা কী ইন্টিপিটিআর ব্যবহার করব? এবং দ্বিতীয়ত, আমরা কীভাবে জানব যে অবজেক্টগুলির একটি সক্রিয় রেফারেন্স রয়েছে?
- বস্তুটি গাদাতে পিন করা যায় এবং এর আসল পয়েন্টারটি সংরক্ষণ করা যায়। জিসি যখন অপসারণের জন্য বস্তুকে আঘাত করে, এটি এটি আনপিন করে এবং সংগ্রহ করে। তবে এর অর্থ হ'ল আমরা একটি পিনযুক্ত সংস্থান পেয়ে যা, আপনার কাছে প্রচুর অবজেক্ট (মেমরি বিভাজনজনিত সমস্যার কারণে) থাকলে এটি ভাল ধারণা নয়। এটি সম্ভবত এটি কাজ করে না।
- জিসি যখন কোনও বস্তু সরিয়ে নিয়ে যায়, তখন এটি আবার কল করে, যা পরে উল্লেখগুলি আপডেট করতে পারে। বাহ্যিক কলগুলি বিচার করে এটি কীভাবে কার্যকর করা যায় তা হতে পারে
DependentHandle
- তবে আমি বিশ্বাস করি এটি কিছুটা পরিশীলিত।
- বস্তুর নিজেই পয়েন্টার নয়, জিসি থেকে সমস্ত বস্তুর তালিকার একটি পয়েন্টার সংরক্ষণ করা হয়। IntPtr হয় এই তালিকার একটি সূচক বা একটি পয়েন্টার। তালিকার তখনই পরিবর্তন হয় যখন কোনও বস্তু প্রজন্মের পরিবর্তন করে, সেই সময়ে একটি সাধারণ কলব্যাক পয়েন্টারগুলিকে আপডেট করতে পারে। আপনি যদি মার্ক ও সুইপ কীভাবে কাজ করে তা মনে রাখেন, এটি আরও অর্থবোধ করে। কোনও পিনিং নেই, এবং অপসারণটি আগের মতো ছিল। আমি বিশ্বাস করি এটি এভাবে কাজ করে
DependentHandle
।
এই শেষ সমাধানটির প্রয়োজন নেই যে রানটাইমগুলি তালিকা বালতিগুলি স্পষ্টভাবে মুক্ত না করা পর্যন্ত পুনরায় ব্যবহার না করে এবং এটিরও প্রয়োজন যে সমস্ত বস্তু রানটাইমে কল করে পুনরুদ্ধার করা উচিত।
যদি আমরা ধরে নিই যে তারা এই সমাধানটি ব্যবহার করে তবে আমরা দ্বিতীয় সমস্যাটিও সমাধান করতে পারি। চিহ্ন এবং সুইপ অ্যালগরিদম কোন বস্তুগুলি সংগ্রহ করা হয়েছে তার উপর নজর রাখে; যত তাড়াতাড়ি এটি সংগ্রহ করা হয়েছে, আমরা এই মুহুর্তে জানি। একবার যখন বস্তুটি সেখানে উপস্থিত আছে কিনা তা পরীক্ষা করে, এটি 'ফ্রি' কল করে, যা পয়েন্টার এবং তালিকার এন্ট্রি সরিয়ে দেয়। বস্তুটি সত্যিই চলে গেছে।
এই মুহুর্তে একটি গুরুত্বপূর্ণ বিষয় লক্ষণীয় ConditionalWeakTable
হ'ল একাধিক থ্রেডে আপডেট করা থাকলে এবং থ্রেডটি নিরাপদ না থাকলে জিনিসগুলি মারাত্মকভাবে ভুল হয়। ফলাফল একটি স্মৃতি ফাঁস হবে। এই কারণেই সমস্ত কলConditionalWeakTable
একটি সাধারণ 'লক' করেন যা নিশ্চিত করে যে এটি ঘটবে না।
আরেকটি বিষয় লক্ষণীয় হ'ল এন্ট্রিগুলি পরিষ্কার করার সময় একবারে ঘটতে হবে। প্রকৃত বস্তুগুলি জিসি দ্বারা পরিষ্কার করা হবে, এন্ট্রিগুলি নেই। এই কারণেই ConditionalWeakTable
কেবল আকারে বৃদ্ধি পায়। একবার এটি একটি নির্দিষ্ট সীমাটি হিট করে (হ্যাশের সংঘর্ষের সুযোগ দ্বারা নির্ধারিত), এটি একটি ট্রিগার করে Resize
, যা পরীক্ষা করে বস্তুগুলি পরিষ্কার করতে হবে কিনা - যদি তা করে, হ্যান্ডেলটি free
সরিয়ে জেসি প্রক্রিয়াতে ডাকা হয় IntPtr
।
আমি বিশ্বাস করি যে এটিও কেন DependentHandle
সরাসরি প্রকাশ করা হয় না - আপনি কোনও জিনিস নিয়ে গোলযোগ করতে চান না এবং ফলস্বরূপ কোনও স্মৃতি ফাঁস হতে চান না। এর জন্য পরবর্তী সেরা জিনিসটি হ'ল একটি WeakReference
(যা কোনও জিনিসের IntPtr
পরিবর্তে একটি সঞ্চয় করে ) - তবে দুর্ভাগ্যক্রমে 'নির্ভরতা' দিকটি অন্তর্ভুক্ত করা হয় না।
মেকানিক্সের সাথে আপনার খেলনা খোলার জন্য যা অবশিষ্ট রয়েছে তা আপনি ক্রিয়ায় নির্ভরতা দেখতে পাচ্ছেন। একাধিকবার এটি শুরু করে ফলাফল দেখুন তা নিশ্চিত করুন:
class DependentObject
{
public class MyKey : IDisposable
{
public MyKey(bool iskey)
{
this.iskey = iskey;
}
private bool disposed = false;
private bool iskey;
public void Dispose()
{
if (!disposed)
{
disposed = true;
Console.WriteLine("Cleanup {0}", iskey);
}
}
~MyKey()
{
Dispose();
}
}
static void Main(string[] args)
{
var dep = new MyKey(true); // also try passing this to cwt.Add
ConditionalWeakTable<MyKey, MyKey> cwt = new ConditionalWeakTable<MyKey, MyKey>();
cwt.Add(new MyKey(true), dep); // try doing this 5 times f.ex.
GC.Collect(GC.MaxGeneration);
GC.WaitForFullGCComplete();
Console.WriteLine("Wait");
Console.ReadLine(); // Put a breakpoint here and inspect cwt to see that the IntPtr is still there
}