Java WeakHashMap والتخزين المؤقت:لماذا تشير إلى المفاتيح وليس القيم؟

StackOverflow https://stackoverflow.com/questions/1802809

  •  05-07-2019
  •  | 
  •  

سؤال

جافا WeakHashMap غالبًا ما يُستشهد به على أنه مفيد للتخزين المؤقت.ولكن يبدو غريبًا أن يتم تحديد مراجعها الضعيفة من حيث مفاتيح الخريطة، وليس قيمها.أعني، إنها القيم التي أريد تخزينها مؤقتًا، والتي أريد جمع البيانات المهملة فيها بمجرد عدم الرجوع إليها بقوة من قبل أي شخص آخر غير ذاكرة التخزين المؤقت، أليس كذلك؟

بأي طريقة يساعد في الاحتفاظ بمراجع ضعيفة للمفاتيح؟إذا قمت ب ExpensiveObject o = weakHashMap.get("some_key"), ، فأنا أريد أن تحتفظ ذاكرة التخزين المؤقت بـ "o" حتى لا يحتفظ المتصل بالمرجع القوي بعد الآن، ولا أهتم على الإطلاق بكائن السلسلة "some_key".

هل فاتني شيء؟

هل كانت مفيدة؟

المحلول

وWeakHashMap <م> لا مفيد باعتباره ذاكرة التخزين المؤقت، أو على الأقل أسلوب معظم الناس يعتقدون ذلك. كما تقول، فإنه يستخدم ضعيفة <م> مفاتيح ، لم يكن ضعيفا <م> القيم ، حتى انها ليست مصممة لماذا معظم الناس يرغبون في استخدامها ل(و، في الواقع، لقد < م> شهدت الناس استخدامها ل، بشكل غير صحيح).

وWeakHashMap هي في معظمها مفيدة للحفاظ على البيانات الوصفية عن الأشياء التي دورة حياة كنت لا السيطرة عليها. على سبيل المثال، إذا كان لديك مجموعة من الأجسام التي تمر عبر صفك، وتريد أن تتبع بيانات إضافية عنهم دون الحاجة إلى أن يتم إعلامك عندما يخرجون من نطاق، ودون رجوع اليها لهم ابقائها على قيد الحياة.

وهناك مثال بسيط (واحد لقد استعملت من قبل) قد يكون شيئا مثل:

WeakHashMap<Thread, SomeMetaData>

وحيث قد تتبع ما المواضيع المختلفة في النظام الخاص بك يفعلون. عندما يموت موضوع، سيتم إزالة إدخال بصمت من الخريطة، وأنك لن تبقي الموضوع من كونه تجميع البيانات المهملة إذا كنت من المرجع الأخير لذلك. يمكنك تكرار ذلك خلال الإدخالات في تلك الخريطة لمعرفة ما لديك بيانات التعريف عن المواضيع النشطة في النظام.

WeakHashMap في عدم مخبأ! لمزيد من المعلومات.

لنوع من مخبأ كنت بعد، إما استخدام نظام مخبأ مخصص (مثل EHCache ) أو النظر في جوجل-مجموعات " <لأ href =" HTTP: //google-collections.googlecode كوم / إس / جذع / جافادوك / كوم / جوجل / مشترك / جمع / MapMaker.html "يختلط =" noreferrer "> مصمم الخرائط الطبقة . شيء من هذا القبيل

new MapMaker().weakValues().makeMap();

وسوف تفعل ما كنت بعد، أو إذا كنت ترغب في الحصول على الهوى يمكنك إضافة انتهاء توقيت:

new MapMaker().weakValues().expiration(5, TimeUnit.MINUTES).makeMap();

نصائح أخرى

والاستخدام الرئيسي لWeakHashMap هو عندما يكون لديك تعيينات الذي تريد أن تختفي عندما تختفي المفاتيح الخاصة بهم. مخبأ هو العكس --- لديك تعيينات الذي تريد أن تختفي عندما تختفي قيمها.

لمخبأ، ما تريده هو Map<K,SoftReference<V>>. A SoftReference سيكون garbage- جمعت عندما يحصل ذاكرة ضيقة. (قارن هذا مع WeakReference، والتي قد يتم مسح في أقرب وقت لم يعد هناك إشارة الصعب المرجع لها.) أنت تريد المراجع الخاصة بك لتكون لينة في ذاكرة التخزين المؤقت (على الأقل في واحد حيث لا تذهب تعيينات قيمة مفتاح قديمة)، منذ ذلك الحين هناك فرصة أن القيم الخاصة بك وسوف يكون لا يزال في ذاكرة التخزين المؤقت إذا كنت تبحث عن لاحقا. إذا كانت الإشارات الضعيفة بدلا من ذلك، سوف gc'd القيم الخاصة بك على الفور، هزيمة الغرض من التخزين المؤقت.

لراحة، قد ترغب في إخفاء القيم SoftReference داخل تنفيذ Map الخاص بك، بحيث يظهر ذاكرة التخزين المؤقت لتكون من نوع <K,V> بدلا من <K,SoftReference<V>>. إذا كنت تريد أن تفعل ذلك، هذا السؤال ديه اقتراحات لتطبيقات المتاحة على الشبكة.

ملحوظة أيضا أنه عند استخدام القيم SoftReference في Map، أنت <م> يجب تفعل شيئا لإزالة أزواج قيمة المفتاح-التي كان SoftReferences على مسح يدويا --- خلاف ذلك Map الخاص بك وسوف تنمو فقط في حجم إلى الأبد، وتسرب الذاكرة.

وشيء آخر للنظر هو أنه إذا كنت تأخذ النهج Map<K, WeakReference<V>>، قد تختفي القيمة، ولكن تعيين لا. حسب الاستخدام، قد ونتيجة لذلك ينتهي مع خريطة تحتوي على العديد من الإدخالات التي تم GC'd المراجع ضعيف.

تحتاج إلى خريطتين:واحد يقوم بالتخطيط بين مفتاح ذاكرة التخزين المؤقت و مرجع ضعيف القيم وواحدة في الاتجاه المعاكس لتعيين القيم المرجعية الضعيفة والمفاتيح.وتحتاج إلى قائمة الانتظار المرجعية وخيط التنظيف.

تتمتع المراجع الضعيفة بالقدرة على نقل المرجع إلى قائمة الانتظار عندما يتعذر الوصول إلى الكائن المشار إليه بعد الآن.يجب أن يتم استنزاف قائمة الانتظار هذه بواسطة مؤشر ترابط التنظيف. وللتنظيف من الضروري الحصول على مفتاح مرجعي. وهذا هو سبب الحاجة إلى الخريطة الثانية.

يوضح المثال التالي كيفية إنشاء ذاكرة تخزين مؤقت باستخدام خريطة تجزئة للمراجع الضعيفة.عند تشغيل البرنامج تحصل على المخرجات التالية:

$ javac -Xlint:unchecked Cache.java && java Cache
{even: [2, 4, 6], odd: [1, 3, 5]}
{even: [2, 4, 6]}

يعرض السطر الأول محتويات ذاكرة التخزين المؤقت قبل حذف المرجع إلى القائمة الفردية والسطر الثاني بعد حذف الاحتمالات.

هذا هو الرمز:

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class Cache<K,V>
{
    ReferenceQueue<V> queue = null;
    Map<K,WeakReference<V>> values = null;
    Map<WeakReference<V>,K> keys = null;
    Thread cleanup = null;

    Cache ()
    {
        queue  = new ReferenceQueue<V>();
        keys   = Collections.synchronizedMap (new HashMap<WeakReference<V>,K>());
        values = Collections.synchronizedMap (new HashMap<K,WeakReference<V>>());
        cleanup = new Thread() {
                public void run() {
                    try {
                        for (;;) {
                            @SuppressWarnings("unchecked")
                            WeakReference<V> ref = (WeakReference<V>)queue.remove();
                            K key = keys.get(ref);
                            keys.remove(ref);
                            values.remove(key);
                        }
                    }
                    catch (InterruptedException e) {}
                }
            };
        cleanup.setDaemon (true);
        cleanup.start();
    }

    void stop () {
        cleanup.interrupt();
    }

    V get (K key) {
        return values.get(key).get();
    }

    void put (K key, V value) {
        WeakReference<V> ref = new WeakReference<V>(value, queue);
        keys.put (ref, key);
        values.put (key, ref);
    }

    public String toString() {
        StringBuilder str = new StringBuilder();
        str.append ("{");
        boolean first = true;
        for (Map.Entry<K,WeakReference<V>> entry : values.entrySet()) {
            if (first)
                first = false;
            else
                str.append (", ");
            str.append (entry.getKey());
            str.append (": ");
            str.append (entry.getValue().get());
        }
        str.append ("}");
        return str.toString();
    }

    static void gc (int loop, int delay) throws Exception
    {
        for (int n = loop; n > 0; n--) {
            Thread.sleep(delay);
            System.gc(); // <- obstinate donkey
        }
    }

    public static void main (String[] args) throws Exception
    {
        // Create the cache
        Cache<String,List> c = new Cache<String,List>();

        // Create some values
        List odd = Arrays.asList(new Object[]{1,3,5});
        List even = Arrays.asList(new Object[]{2,4,6});

        // Save them in the cache
        c.put ("odd", odd);
        c.put ("even", even);

        // Display the cache contents
        System.out.println (c);

        // Erase one value;
        odd = null;

        // Force garbage collection
        gc (10, 10);

        // Display the cache again
        System.out.println (c);

        // Stop cleanup thread
        c.stop();
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top