.NET অনন্য বস্তু শনাক্তকারী ier


118

কোনও দৃষ্টান্তের অনন্য সনাক্তকারী হওয়ার কোনও উপায় আছে কি?

GetHashCode()দুটি একই রেফারেন্সের দিকে নির্দেশ করে রেফারেন্সের জন্য একই। তবে দুটি পৃথক দৃষ্টান্ত (বেশ সহজেই) একই হ্যাশ কোডটি পেতে পারে:

Hashtable hashCodesSeen = new Hashtable();
LinkedList<object> l = new LinkedList<object>();
int n = 0;
while (true)
{
    object o = new object();
    // Remember objects so that they don't get collected.
    // This does not make any difference though :(
    l.AddFirst(o);
    int hashCode = o.GetHashCode();
    n++;
    if (hashCodesSeen.ContainsKey(hashCode))
    {
        // Same hashCode seen twice for DIFFERENT objects (n is as low as 5322).
        Console.WriteLine("Hashcode seen twice: " + n + " (" + hashCode + ")");
        break;
    }
    hashCodesSeen.Add(hashCode, null);
}

আমি একটি ডিবাগিং অ্যাডিন লিখছি, এবং আমার একটি রেফারেন্সের জন্য এক ধরণের আইডি নেওয়া দরকার যা প্রোগ্রামটি চলাকালীন অনন্য।

আমি ইতিমধ্যে উদাহরণটির অভ্যন্তরীণ অ্যাড্রেস পেয়েছি, যা আবর্জনা সংগ্রহকারী (জিসি) গাদা (= বস্তুগুলিকে সরিয়ে দেয় = ঠিকানা পরিবর্তন করে) অবধি যোগাযোগ না করা অবধি অনন্য।

ওভারফ্লো প্রশ্ন স্ট্যাক ওজেক্টের জন্য ডিফল্ট বাস্তবায়ন et গেটহ্যাশকোড () এর সাথে সম্পর্কিত হতে পারে।

ডিবাগার এপিআই ব্যবহার করে ডিবাগ করা হচ্ছে এমন কোনও প্রোগ্রামে আমি অবজেক্টগুলিতে অ্যাক্সেস করছি বলে অবজেক্টগুলি আমার নিয়ন্ত্রণে নেই। যদি আমি অবজেক্টগুলির নিয়ন্ত্রণে থাকি তবে আমার নিজস্ব অনন্য শনাক্তকারী যুক্ত করা তুচ্ছ v

আমি হ্যাশটেবল আইডি -> অবজেক্ট তৈরির জন্য অনন্য আইডি চেয়েছিলাম, ইতিমধ্যে দেখা বস্তুগুলি অনুসন্ধান করতে সক্ষম হব। আপাতত আমি এটি এর মতো সমাধান করেছি:

Build a hashtable: 'hashCode' -> (list of objects with hash code == 'hashCode')
Find if object seen(o) {
    candidates = hashtable[o.GetHashCode()] // Objects with the same hashCode.
    If no candidates, the object is new
    If some candidates, compare their addresses to o.Address
        If no address is equal (the hash code was just a coincidence) -> o is new
        If some address equal, o already seen
}

উত্তর:


42

রেফারেন্সটি হ'ল বস্তুর জন্য অনন্য শনাক্তকারী। এটিকে স্ট্রিং ইত্যাদির মতো কোনও কিছুর মধ্যে রূপান্তর করার কোনও উপায় আমি জানি না রেফারেন্সের মানটি কমপ্যাকশন চলাকালীন পরিবর্তিত হবে (যেমনটি আপনি দেখেছেন), তবে প্রতিটি পূর্ববর্তী মান A তে মান B তে পরিবর্তিত হবে নিরাপদ কোড হিসাবে এটি এখনও একটি অনন্য আইডি উদ্বিগ্ন।

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


1
আমার ধারণা আপনি যে সমস্ত রেফারেন্সগুলি ট্র্যাক করেছেন তার উপর আপনাকে পুনরাবৃত্তি করতে হবে: একই অবজেক্টের WeakReferences একে অপরের সমান নয়, সুতরাং আপনি সত্যিই আরও কিছু করতে পারবেন না।
রোমান স্টারকভ

1
প্রতিটি বস্তুকে একটি অনন্য 64৪-বিট আইডি অর্পণ করার কিছুটা উপযোগিতা থাকতে পারে, বিশেষত যদি এই জাতীয় আইডিগুলি ধারাবাহিকভাবে জারি করা হয়। আমি নিশ্চিত নই যে উপকারীতা ব্যয়টিকে ন্যায্য করে তুলবে, তবে এইরকম জিনিস সহায়ক হতে পারে যদি কেউ দুটি স্বতন্ত্র অপরিবর্তনীয় বস্তুর তুলনা করে তাদের সমান দেখতে পায়; যদি কেউ সম্ভব হয় পুরানোটির সাথে একটি রেফারেন্স সহ নতুনটির রেফারেন্সটি ওভাররাইট করে দেয় তবে একটি অভিন্ন কিন্তু স্বতন্ত্র বস্তুর সাথে অনেকগুলি অতিরিক্ত বাজে রেফারেন্স এড়াতে পারে।
সুপারক্যাট

1
"আইডেন্টিফাইয়ার।" আমি মনে করি না যে এই শব্দটির অর্থ আপনি যা ভাবেন তার অর্থ।
স্লিপ ডি থম্পসন

5
@ স্লিপডি.টমসন: না, এটি এখনও 1-থেকে -1 সম্পর্ক। এখানে কেবল একটি একক রেফারেন্স মান রয়েছে যা কোনও প্রদত্ত বস্তুকে বোঝায়। সেই মানটি মেমরিতে বহুবার উপস্থিত হতে পারে (যেমন একাধিক ভেরিয়েবলের মান হিসাবে) তবে এটি এখনও একক মান। এটি কোনও বাড়ির ঠিকানার মতো: আমি আমার বাড়ির ঠিকানা একাধিক কাগজের টুকরোতে লিখে রাখতে পারি, তবে এটি এখনও আমার বাড়ির সনাক্তকারী। যেকোনও দুটি অ-অভিন্ন রেফারেন্স মানগুলি অবশ্যই পৃথক অবজেক্টের সাথে উল্লেখ করতে হবে - কমপক্ষে সি # তে।
জন স্কিটি

1
@ সুপের্যাট: আমি মনে করি আমাদের "সনাক্তকরণগুলি সনাক্তকরণ" সম্পর্কে আমাদের ধারণার মধ্যে পৃথক হতে পারে - তবে আমি মনে করি আমরা সম্ভবত ইতিমধ্যে আমাদের কাউকে আর যেতে সাহায্য করছি না :) কেবলমাত্র আমাদের বিষয়গুলির একটি মাত্র যদি আমাদের দৈর্ঘ্যে আলোচনা করা উচিত তবে আমরা কখনও ব্যক্তিগতভাবে দেখা করি ...
জন স্কিটি

72

.NET 4 এবং পরে কেবল

সুখবর, সবাই!

এই কাজের জন্য নিখুঁত সরঞ্জামটি নেট 4 এ তৈরি করা হয়েছে এবং এটি ডাকা হয় ConditionalWeakTable<TKey, TValue>। এই বর্গ:

  • পরিচালিত অবজেক্টের উদাহরণগুলির সাথে অনেকগুলি অভিধানের মতো স্বেচ্ছাসেবক ডেটা সংযুক্ত করতে ব্যবহার করা যেতে পারে (যদিও তা হয় একটি অভিধান নয়)
  • মেমরি ঠিকানার উপর নির্ভর করে না, তাই জিসি হিপটি সংশ্লেষ করে imm
  • কেবলমাত্র টেবিলের চাবি হিসাবে প্রবেশ করার কারণে বস্তুগুলিকে জীবিত রাখে না, তাই এটি আপনার প্রক্রিয়াটির প্রতিটি বস্তু চিরকাল জীবন্ত না করে ব্যবহার করা যেতে পারে
  • বস্তুর পরিচয় নির্ধারণের জন্য রেফারেন্স সাম্যতা ব্যবহার করে; মুভওভার, শ্রেণি লেখকরা এই আচরণটি পরিবর্তন করতে পারবেন না যাতে এটি ধারাবাহিকভাবে ব্যবহার করা যায় কোনও ধরণের অবজেক্টগুলিতে করা যায়
  • ফ্লাইতে জনবহুল হতে পারে, তাই আপনাকে অবজেক্ট কনস্ট্রাক্টরের ভিতরে কোড ইনজেক্ট করার প্রয়োজন নেই

5
কেবল সম্পূর্ণতার জন্য: এর অভ্যন্তরীণ কাজগুলি ConditionalWeakTableউপর নির্ভর করে RuntimeHelpers.GetHashCodeএবং object.ReferenceEqualsকরতে পারে। IEqualityComparer<T>এই দুটি পদ্ধতি ব্যবহার করে এমনটি নির্মাণের মতো আচরণ একই same আপনার যদি পারফরম্যান্সের প্রয়োজন হয় তবে আমি আসলে এটি করার পরামর্শ দিচ্ছি, যেহেতু ConditionalWeakTableথ্রেডটিকে সুরক্ষিত করার জন্য এর সমস্ত ক্রিয়াকলাপের একটি লক রয়েছে।
আটলস্টে

1
@ স্টেফান্ডে ব্রুইজন: এ এর ConditionalWeakTableপ্রত্যেকটির একটি রেফারেন্স রয়েছে Valueযা কেবল অন্যত্র সম্পর্কিত রেফারেন্সের মতোই শক্তিশালী KeyConditionalWeakTableমহাবিশ্বের যে কোনও জায়গায় কেবলমাত্র একমাত্র বিদ্যমান রেফারেন্স ধারণ করে এমন একটি বস্তু যখন কীটি করলে তা স্বয়ংক্রিয়ভাবে অস্তিত্ব বন্ধ হয়ে যাবে।
সুপারক্যাট

41

অবজেক্টআইডি জেনারেটর ক্লাস চেক আউট ? এটি আপনি যা করার চেষ্টা করছেন তা এবং মার্ক গ্র্যাভেল যা বর্ণনা করে তা করে।

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

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

একটি হ্যাশ টেবিল ব্যবহার করে, অবজেক্টআইডি জেনারেটরটি কোন আইডিটি কোন বস্তুর জন্য নির্ধারিত তা ধরে রাখে। অবজেক্টের রেফারেন্সগুলি, যা প্রতিটি বস্তুকে স্বতন্ত্রভাবে সনাক্ত করে, রানটাইম আবর্জনা-সংগৃহীত হিপগুলির ঠিকানা। সিরিয়ালাইজেশনের সময় অবজেক্টের রেফারেন্স মানগুলি পরিবর্তন করতে পারে তবে তথ্যটি সঠিক হওয়ার সাথে সাথে সারণিটি স্বয়ংক্রিয়ভাবে আপডেট হয়।

অবজেক্ট আইডি 64৪-বিট সংখ্যা। বরাদ্দ এক থেকে শুরু হয়, তাই শূন্য কখনই একটি বৈধ অবজেক্ট আইডি হয় না। একটি বিন্যাসক একটি বস্তুর রেফারেন্স উপস্থাপনের জন্য একটি শূন্য মান চয়ন করতে পারে যার মান নাল রেফারেন্স (ভিজ্যুয়াল বেসিকের কিছুই নয়)।


5
রিফ্লেক্টর আমাকে বলে যে অবজেক্টআইডিজেনারেটর হ্যাশটেবল যা ডিফল্ট গেটহ্যাশকোড প্রয়োগের উপর নির্ভর করে (যেমন এটি ব্যবহারকারীর ওভারলোডগুলি ব্যবহার করে না)।
আন্তন টিখি

মুদ্রণযোগ্য অনন্য আইডি প্রয়োজন হলে সম্ভবত সেরা সমাধান।
রোমান স্টারকভ

অবজেক্টআইডিজেনারেটর ফোনটিতে প্রয়োগ করা হয় না।
অ্যান্টনি উইজার

অবজেক্টআইডিজেনেটর ঠিক কী করছে তা আমি বুঝতে পারি না তবে এটি রানটাইমহেল্পার্স.গেটহ্যাশকোড ব্যবহার করার পরেও এটি কার্যকর বলে মনে হচ্ছে। আমি এবং কেবল রানটাইমহেলপার্স উভয়ই পরীক্ষা করেছিলাম et গেটহ্যাশকড আমার ক্ষেত্রে ব্যর্থ।
ড্যানিয়েল বিয়ার 16

+1 - বেশ চতুর কাজ করে (ডেস্কটপে অন্তত)।
হট লিক্স

37

RuntimeHelpers.GetHashCode()সাহায্য করতে পারে ( এমএসডিএন )


2
এটি ভাল সাহায্য করতে পারে, তবে ব্যয় সহ - আইআইআরসি, বেস অবজেক্টটি ব্যবহার করে et গেটহ্যাশকোড () একটি সিঙ্ক ব্লক বরাদ্দ করতে হবে যা নিখরচায় নয়। যদিও ভাল ধারণা - আমার কাছ থেকে +1।
জন স্কিটি

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

1
আপনার যদি খুব বেশি সংখ্যক প্রয়োজন না হয় তবে আপনি নীচে দেখুন) GCHandle ব্যবহার করতে পারেন।
আন্তন টিখি

42
একটি অত্যন্ত সম্মানিত লেখকের দ্বারা .NET- র একটি বইতে বলা হয়েছে যে রানটাইমহেল্পার্স.গেটহ্যাশকোড () একটি কোড তৈরি করবে যা একটি অ্যাপডোমাইনের মধ্যে অনন্য এবং মাইক্রোসফ্ট এই পদ্ধতিটির নাম গিটউনিকিউজেক্টআইডি দিতে পারে। এটি কেবল ভুল। পরীক্ষায়, আমি দেখতে পেলাম যে আমি যখন কোনও বস্তুর 10,000 টি উদাহরণ তৈরি করেছি (উইনফর্মস টেক্সটবক্স) তখন আমি সাধারণত একটি নকল পেতে পারি এবং কখনই 30,000 ছাড়তে পারি না। অনুমান করা স্বতন্ত্রতার উপর নির্ভরশীল কোডের ফলে অনেকগুলি বস্তু 1/10 এর বেশি তৈরি না করে একটি প্রোডাকশন সিস্টেমে মাঝে মাঝে ক্র্যাশ ঘটায়।
জান হিটিচ

3
@ সুপের্যাট: আহা - ২০০৩ সাল থেকে কিছু প্রমাণ খুঁজে পেয়েছে, যা নেট নেট ১.০ এবং ১.১ থেকে ছিল। দেখে মনে হচ্ছে যে তারা .NET 2: ব্লগস.এমএসএনএন
স্কিটে

7

আপনি এক সেকেন্ডে নিজের জিনিস বিকাশ করতে পারেন। এই ক্ষেত্রে:

   class Program
    {
        static void Main(string[] args)
        {
            var a = new object();
            var b = new object();
            Console.WriteLine("", a.GetId(), b.GetId());
        }
    }

    public static class MyExtensions
    {
        //this dictionary should use weak key references
        static Dictionary<object, int> d = new Dictionary<object,int>();
        static int gid = 0;

        public static int GetId(this object o)
        {
            if (d.ContainsKey(o)) return d[o];
            return d[o] = gid++;
        }
    }   

উদাহরণস্বরূপ, সিস্টেম.গুইড.ইউইউইউইজিড () বা দ্রুততম অ্যাক্সেসের জন্য কেবল পূর্ণসংখ্যার জন্য আপনি নিজেরাই অনন্য আইডি হিসাবে কী পছন্দ করতে চান তা চয়ন করতে পারেন।


2
আপনার যা প্রয়োজন এটি Disposeবাগগুলি থাকলে সহায়তা করবে না কারণ এটি কোনও ধরণের নিষ্পত্তি রোধ করবে।
রোমান স্টারকভ

1
অভিধানটি পরিচয়ের পরিবর্তে সাম্যতা ব্যবহার করে, বস্তুগুলিকে সঙ্কুচিত করে যে বস্তুগুলির জন্য একই মানগুলি ফেরত দেয় এটি কার্যকরভাবে কাজ করে না quএক্কুলস
অ্যান্টনি উইজার

1
এটি যদিও অবজেক্টটিকে বাঁচিয়ে রাখবে।
মার্টিন লটারিং

1
@ মার্টিনলটারিং যদি তিনি কন্ডিশনাল উইক টেবিল <অবজেক্ট, আইডিটাইপ> ব্যবহার করেন?
ডেমেট্রিস লেপ্টোস

7

এই পদ্ধতি সম্পর্কে:

প্রথম বস্তুতে একটি নতুন মানকে একটি ক্ষেত্র সেট করুন। দ্বিতীয় অবজেক্টের একই ক্ষেত্রের যদি একই মান থাকে তবে এটি সম্ভবত একই উদাহরণ। অন্যথায়, পৃথক হিসাবে প্রস্থান করুন।

এখন প্রথম অবজেক্টে ক্ষেত্রটি একটি নতুন নতুন মান হিসাবে সেট করুন। যদি দ্বিতীয় অবজেক্টের একই ক্ষেত্রটি ভিন্ন মানটিতে পরিবর্তিত হয় তবে এটি অবশ্যই একই উদাহরণ।

প্রস্থান করার সময় প্রথম অবজেক্টে তার মূল মূল্যে ফিরে যেতে ভুলে যাবেন না।

সমস্যা?


4

ভিজ্যুয়াল স্টুডিওতে একটি অনন্য অবজেক্ট আইডেন্টিফায়ার তৈরি করা সম্ভব: ঘড়ির উইন্ডোতে, অবজেক্ট ভেরিয়েবলটি ডান ক্লিক করুন এবং মেক অবজেক্ট আইডি নির্বাচন করুন এবং প্রসঙ্গ মেনু থেকে ।

দুর্ভাগ্যক্রমে, এটি একটি ম্যানুয়াল পদক্ষেপ এবং আমি বিশ্বাস করি না যে সনাক্তকারীকে কোডের মাধ্যমে অ্যাক্সেস করা যেতে পারে।


ভিজ্যুয়াল স্টুডিওর কোন সংস্করণে এই বৈশিষ্ট্যটি রয়েছে? উদাহরণস্বরূপ, এক্সপ্রেস সংস্করণগুলি?
পিটার মর্টেনসেন

3

আপনাকে ম্যানুয়ালি - এইরকম একটি পরিচয়দাতা নিজেকে নিযুক্ত করতে হবে - হয় উদাহরণের অভ্যন্তরে, বা বাহ্যিকভাবে।

একটি ডাটাবেস সম্পর্কিত রেকর্ডগুলির জন্য, প্রাথমিক কীটি কার্যকর হতে পারে (তবে আপনি এখনও নকল পেতে পারেন)। বিকল্পভাবে, হয় একটি ব্যবহার করুন Guid, বা আপনার নিজস্ব কাউন্টার রাখুন, ব্যবহার করে বরাদ্দ করুন Interlocked.Increment(এবং এটি এত বড় করুন যে এটি প্রবাহিত হওয়ার সম্ভাবনা নেই)।


2

আমি জানি যে এটির উত্তর দেওয়া হয়েছে, তবে আপনি এটি ব্যবহার করতে পারেন তা নোট করা কমপক্ষে দরকারী:

http://msdn.microsoft.com/en-us/library/system.object.referenceequals.aspx

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


1

আমি এখানে যে তথ্য দিচ্ছি তা নতুন নয়, আমি এটি সম্পূর্ণতার জন্য যুক্ত করেছি।

এই কোডটির ধারণাটি বেশ সহজ:

  • অবজেক্টগুলির একটি অনন্য আইডি প্রয়োজন, যা ডিফল্টরূপে সেখানে নেই। পরিবর্তে, আমাদের পরবর্তী সেরা জিনিসের উপর নির্ভর 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
    }

1
একটি ConditionalWeakTableভাল হতে পারে, যেহেতু এটি কেবলমাত্র বস্তুর প্রতিনিধিত্ব অব্যাহত রাখে যখন রেফারেন্সগুলি বিদ্যমান থাকে। এছাড়াও, আমি প্রস্তাব দিচ্ছি যে কোনও Int64জিইউডির চেয়ে ভাল হতে পারে, কারণ এটি বস্তুগুলিকে একটি অবিচ্ছিন্ন র‌্যাঙ্ক দেওয়ার অনুমতি দেয় । এ জাতীয় জিনিসগুলি দৃশ্যের লক করার ক্ষেত্রে কার্যকর হতে পারে (উদাহরণস্বরূপ, একাধিক লক অর্জন করতে হবে এমন সমস্ত কোড কিছু সংজ্ঞায়িত ক্রমে যদি তা করে থাকে তবে এটি কাজ করার জন্য একটি সংজ্ঞায়িত ক্রম থাকতে হবে )।
সুপারক্যাট

@ সুপের্যাট longএস সম্পর্কে নিশ্চিত এটি আপনার দৃশ্যের উপর নির্ভর করে - এফ.এক্স. বিতরণ সিস্টেম এটি এর সাথে কাজ করতে কখনও কখনও আরও দরকারী GUID। যেমন ConditionalWeakTable: আপনি ঠিক বলেছেন; DependentHandleবেঁচে থাকার জন্য চেক করুন (দ্রষ্টব্য: কেবলমাত্র যখন জিনিসটির আকার পরিবর্তিত হয়!), যা এখানে দরকারী হতে পারে। তবুও, যদি আপনার কর্মক্ষমতা প্রয়োজন হয় তবে লকিংটি সেখানে একটি সমস্যা হয়ে উঠতে পারে, সুতরাং সেই ক্ষেত্রে এটি ব্যবহার করা আকর্ষণীয় হতে পারে ... সত্যি কথা বলতে আমি ব্যক্তিগতভাবে এর প্রয়োগটি অপছন্দ করি ConditionalWeakTable, যা সম্ভবত আমার সাধারণ ব্যবহারের পক্ষপাতিত্বের দিকে পরিচালিত করে Dictionary- এমনকি যদিও আপনি সঠিক
আটলাস্ট

আমি কীভাবে ConditionalWeakTableআসলে কাজ করে তা সম্পর্কে দীর্ঘকাল আগ্রহী ছিলাম । এটি কেবলমাত্র আইটেম যুক্ত করার অনুমতি দেয় তা আমাকে ভাবতে বাধ্য করে যে এটি একত্রে-সম্পর্কিত ওভারহেড হ্রাস করার জন্য তৈরি করা হয়েছে, তবে এটি অভ্যন্তরীণভাবে কীভাবে কাজ করে তা আমার কোনও ধারণা নেই। আমি এটি কৌতূহলী মনে করি যে কোনও সাধারণ DependentHandleমোড়ক নেই যা কোনও টেবিল ব্যবহার করে না, কারণ এমন অনেক সময় অবশ্যই পাওয়া উচিত যখন একটি বিষয়টিকে অন্যের জীবদ্দশায় জীবিত রাখা হয় তবে এটি পরবর্তী বিষয়টির রেফারেন্সের জন্য কোনও জায়গা নেই প্রথম থেকে.
সুপারক্যাট

@ সুপের্যাট আমি কীভাবে এটি কাজ করে বলে মনে করি তার একটি সংযোজন পোস্ট করব।
আটলস্টে

ConditionalWeakTableএন্ট্রি অনুমতি দেয় না যা টেবিল সঞ্চিত হয়েছে পরিবর্তিত হতে পারে। এর মতো, আমি মনে করব যে এটি লকগুলি নয় মেমরির বাধা ব্যবহার করে নিরাপদে প্রয়োগ করা যেতে পারে। সমস্যাযুক্ত পরিস্থিতি কেবল তখনই হবে যদি দুটি থ্রেড একই সাথে একই কী যুক্ত করার চেষ্টা করে; কোনও আইটেম যুক্ত হওয়ার পরে "অ্যাড" পদ্ধতিটি একটি মেমরি বাধা সঞ্চালন করে সমাধান করতে পারে এবং তারপরে একটি আইটেমের কীটি রয়েছে তা নিশ্চিত করার জন্য স্ক্যান করে। যদি একাধিক আইটেমের একই কী থাকে তবে এর মধ্যে একটির "প্রথম" হিসাবে চিহ্নিত করা যাবে, তাই অন্যগুলি মুছে ফেলা সম্ভব হবে।
সুপারক্যাট

0

আপনি যদি একটি নির্দিষ্ট ব্যবহারের জন্য আপনার নিজের কোডে একটি মডিউল লেখা হয়, majkinetor এর পদ্ধতি পারে কাজ করেছি। তবে কিছু সমস্যা আছে।

প্রথমত , সরকারী দস্তাবেজ কোনও গ্যারান্টি দেয় না যে GetHashCode()রিটার্নগুলি একটি অনন্য শনাক্তকারীকে দেয় ( অবজেক্ট.গেটহ্যাশকোড পদ্ধতি ( ) দেখুন:

আপনার ধরে নেওয়া উচিত নয় যে সমান হ্যাশ কোডগুলি সমতাকে বোঝায়।

দ্বিতীয়ত , ধরে নিন আপনার কাছে খুব অল্প পরিমাণে অবজেক্ট রয়েছে যাতে GetHashCode()বেশিরভাগ ক্ষেত্রে এটি কাজ করবে, এই পদ্ধতিটি কিছু ধরণের দ্বারা ওভাররাইড করা যেতে পারে।
উদাহরণস্বরূপ, আপনি কিছু ক্লাস সি ব্যবহার করছেন এবং এটি GetHashCode()সর্বদা 0. ফিরে আসার জন্য ওভাররাইড করে Then তারপরে সি এর প্রতিটি বস্তু একই হ্যাশ কোড পাবে। দুর্ভাগ্যবশত, Dictionary, HashTableএবং কিছু অন্যান্য মিশুক পাত্রে এই পদ্ধতি ব্যবহার করবে:

একটি হ্যাশ কোড হ'ল একটি সাংখ্যিক মান যা হ্যাশ-ভিত্তিক সংগ্রহ যেমন একটি অভিধান <টিকি, টিভিয়াল্য> শ্রেণি, হ্যাশটেবল শ্রেণি, বা অভিধানব্যাস ক্লাস থেকে প্রাপ্ত কোনও প্রকারের মতো কোনও বস্তু সন্নিবেশ এবং সনাক্ত করতে ব্যবহৃত হয়। গেটহ্যাশকোড পদ্ধতিটি অ্যালগরিদমের জন্য এই হ্যাশ কোডটি সরবরাহ করে যার জন্য অবজেক্টের সাম্যের দ্রুত চেক প্রয়োজন।

সুতরাং, এই পদ্ধতির দুর্দান্ত সীমাবদ্ধতা রয়েছে।

এবং আরও বেশি , আপনি যদি একটি সাধারণ উদ্দেশ্য গ্রন্থাগার তৈরি করতে চান? আপনি ব্যবহৃত ক্লাসগুলির উত্স কোডটি কেবলমাত্র সংশোধন করতে সক্ষম নন, তবে তাদের আচরণটিও অনাকাঙ্ক্ষিত।

আমি প্রশংসা করি যে জোন এবং সাইমন তাদের উত্তর পোস্ট করেছে, এবং আমি নীচের পারফরম্যান্সের জন্য একটি কোড উদাহরণ এবং একটি পরামর্শ পোস্ট করব।

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Collections.Generic;


namespace ObjectSet
{
    public interface IObjectSet
    {
        /// <summary> check the existence of an object. </summary>
        /// <returns> true if object is exist, false otherwise. </returns>
        bool IsExist(object obj);

        /// <summary> if the object is not in the set, add it in. else do nothing. </summary>
        /// <returns> true if successfully added, false otherwise. </returns>
        bool Add(object obj);
    }

    public sealed class ObjectSetUsingConditionalWeakTable : IObjectSet
    {
        /// <summary> unit test on object set. </summary>
        internal static void Main() {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            ObjectSetUsingConditionalWeakTable objSet = new ObjectSetUsingConditionalWeakTable();
            for (int i = 0; i < 10000000; ++i) {
                object obj = new object();
                if (objSet.IsExist(obj)) { Console.WriteLine("bug!!!"); }
                if (!objSet.Add(obj)) { Console.WriteLine("bug!!!"); }
                if (!objSet.IsExist(obj)) { Console.WriteLine("bug!!!"); }
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
        }


        public bool IsExist(object obj) {
            return objectSet.TryGetValue(obj, out tryGetValue_out0);
        }

        public bool Add(object obj) {
            if (IsExist(obj)) {
                return false;
            } else {
                objectSet.Add(obj, null);
                return true;
            }
        }

        /// <summary> internal representation of the set. (only use the key) </summary>
        private ConditionalWeakTable<object, object> objectSet = new ConditionalWeakTable<object, object>();

        /// <summary> used to fill the out parameter of ConditionalWeakTable.TryGetValue(). </summary>
        private static object tryGetValue_out0 = null;
    }

    [Obsolete("It will crash if there are too many objects and ObjectSetUsingConditionalWeakTable get a better performance.")]
    public sealed class ObjectSetUsingObjectIDGenerator : IObjectSet
    {
        /// <summary> unit test on object set. </summary>
        internal static void Main() {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            ObjectSetUsingObjectIDGenerator objSet = new ObjectSetUsingObjectIDGenerator();
            for (int i = 0; i < 10000000; ++i) {
                object obj = new object();
                if (objSet.IsExist(obj)) { Console.WriteLine("bug!!!"); }
                if (!objSet.Add(obj)) { Console.WriteLine("bug!!!"); }
                if (!objSet.IsExist(obj)) { Console.WriteLine("bug!!!"); }
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
        }


        public bool IsExist(object obj) {
            bool firstTime;
            idGenerator.HasId(obj, out firstTime);
            return !firstTime;
        }

        public bool Add(object obj) {
            bool firstTime;
            idGenerator.GetId(obj, out firstTime);
            return firstTime;
        }


        /// <summary> internal representation of the set. </summary>
        private ObjectIDGenerator idGenerator = new ObjectIDGenerator();
    }
}

আমার পরীক্ষায়, ObjectIDGeneratorলুপটিতে 10,000,000 অবজেক্ট (উপরের কোডের তুলনায় 10x) তৈরি করার সময় অনেকগুলি অবজেক্ট রয়েছে এমন অভিযোগের জন্য প্রতিবেদনটি ব্যতিক্রম করবে for

এছাড়াও, ConditionalWeakTableমাপদণ্ডের ফলাফলটি ObjectIDGeneratorবাস্তবায়নের চেয়ে 1.8x দ্রুত হয় ।

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