هناك أربعة أنواع مرجعية في Java/Android ، وهي:
مرجع قوي - مرجع قوي
مرجع ناعم - مرجع ناعم
مرجع ضعيف - مرجع ضعيف
مرجع الوهمية - اقتباس افتراضي
الأنواع المرجعية المختلفة لها خصائص مختلفة وتتوافق أيضًا مع سيناريوهات الاستخدام المختلفة.
1. المرجع المرجعي - مرجع قوي
النوع الأكثر شيوعا للمرجع في الترميز الفعلي. أشكال شائعة مثل: A = جديد A () ؛ إلخ. يتم تخزين المرجع القوي نفسه في ذاكرة المكدس ، ويخزن العنوان للكائن في الذاكرة. بشكل عام ، عندما لم يعد هناك أي إشارة قوية إلى الكائن في الذاكرة يشير إليه ، تبدأ آلة جمع القمامة في التفكير في مجموعة القمامة التي يمكن القيام بها على هذه الذاكرة. إذا كانت الترميز: A = NULL ، في هذا الوقت ، فإن العنوان الذي تم تخصيصه للتو في الكومة وإنشاء ليس له أي مراجع أخرى. عندما يقوم النظام بإجراء جمع القمامة ، سيتم جمع ذاكرة الكومة.
Softreference ، الضعف ، و phantomreference كلها فئات فرعية من الفئة java.lang.ref.reference. المرجع ، باعتبارها فئة قاعدة مجردة ، تحدد العمليات الأساسية لكائنات الفئة الفرعية. جميع الفئات الفرعية المرجعية لها الخصائص التالية:
1. لا يمكن إنشاء الفئة الفرعية المرجعية مباشرة دون تحديد المعلمة. يجب على الأقل استخدام الكائن المرجعي القوي كمعلمة بناء لإنشاء كائنات الفئة الفرعية الخاصة بها ؛
2. نظرًا لأن الكائن يتم إنشاؤه في 1 مع كائن مرجعي قوي كمعلمة بناء ، فإن الكائنات الموجودة في ذاكرة الكومة التي أشار إليها المرجع القوي في الأصل لن تكون مرتبطة مباشرة بالمرجع القوي نفسه ، ولكن سيكون لها أيضًا اتصال معين مع مرجع كائن المرجع الفرعي. وقد يؤثر هذا الاتصال على جمع القمامة للكائن.
وفقًا لخصائص التأثير المختلفة للكائنات الفرعية المختلفة على جمع القمامة من كائنات المؤشر الخاصة بهم (إشارات قوية إلى الكائنات في ذاكرة الكومة التي تشير إليها) ، يتم تشكيل ثلاث فئات فرعية ، وهي الإحالة ، الضعيفة ، الفصح.
2. مرجع Soft - مرجع ناعم
شكل الاستخدام العام للمرجع الناعم هو كما يلي:
a = جديد a () ؛
softreference <a> sra = new softreference <a> (a) ؛
من خلال المرجع القوي للكائن كمعلمة ، يتم إنشاء كائن softreference ويشير WRA في ذاكرة المكدس إلى هذا الكائن.
في هذا الوقت ، يتم تنفيذ الترميز التالي: a = null. ما هو تأثيرها على مجموعة القمامة للكائن الذي أشار إليه في الأصل؟
دعنا نلقي نظرة على نتائج إخراج البرنامج التالي:
استيراد java.lang.ref.softreference ؛ الفئة العامة المرجعية {public static void main (string [] args) {a a = new a () ؛ softreference <a> sra = new softreference <a> (a) ؛ أ = خالية ؛ if (sra.get () == null) {system.out.println ("يدخل كائن عملية جمع القمامة") ؛ } آخر {system.out.println ("لم يتم إعادة تدوير كائن بعد" + sra.get ()) ؛ } // Garbage Collection System.gc () ؛ if (sra.get () == null) {system.out.println ("كائن يدخل عملية جمع القمامة") ؛ } آخر {system.out.println ("لم يتم إعادة تدوير كائن بعد" + sra.get ()) ؛ }}} الفئة A {} ## نتيجة الإخراج هي:
1 لم يتم إعادة تدوير كائن@4807ccf62 لم يتم إعادة تدوير كائن@4807ccf6
عندما لا يكون ذلك = null ، لن يكون للكائن الموجود في ذاكرة الكومة أي إشارات قوية إليه ، ولكن هناك كائن عصري يشار إليه SRA يشير إلى كائن A. عندما يتم استدعاء طريقة sra.get () لأول مرة لإرجاع كائن المؤشر هذا ، نظرًا لأن جامع القمامة من المحتمل ألا يقوم بعد بمجتمع القمامة ، فإن الحصول على () له نتيجة في هذا الوقت ، وهو أمر سهل الفهم. عندما ينفذ البرنامج system.gc () ؛ إجبار جمع القمامة ، من خلال sra.get () ، وجد أنه لا يزال من الممكن الحصول على كائن مشار إليه ، مما يشير إلى أن الكائن لم يتم جمعه. لذا ، متى ستبدأ الكائنات المشار إليها بالمرجع الناعم في جمع القمامة؟ يجب الوفاء بالشرطين التاليين:
1. عندما يشير الكائن الذي يشير إلى أي كائن مرجعي قوي يشير إليه ؛
2. عندما يكون للجهاز الظاهري ذاكرة غير كافية.
لذلك ، يمتد Softreference الوقت الذي يشير فيه إلى أن الكائن يحتل ذاكرة الكومة حتى يتمتع الجهاز الظاهري بذاكرة غير كافية. لا يقوم جامع القمامة بإعادة تدوير مساحة ذاكرة الكومة هذه.
3. مرجعية - مرجع ضعيف
وبالمثل ، فإن شكل الاستخدام العام للمرجع الناعم هو كما يلي:
a = جديد a () ؛
PreferReference <a> wra = new Preferference <a> (a) ؛
عندما لا يكون هناك إشارة قوية تشير إلى هذا الكائن ، ما هي خصائص جمع القمامة؟
استيراد java.lang.ref.weakReference ؛ الفئة العامة المرجعية {public static void main (string [] args) {a a = new a () ؛ PreferReference <a> wra = new Preferference <a> (a) ؛ أ = خالية ؛ if (wra.get () == null) {system.out.println ("يدخل كائن عملية جمع القمامة") ؛ } آخر {system.out.println ("لم يتم إعادة تدوير كائن بعد" + wra.get ()) ؛ } // Garbage Collection System.gc () ؛ if (wra.get () == null) {system.out.println ("كائن يدخل عملية جمع القمامة") ؛ } آخر {system.out.println ("لم يتم إعادة تدوير كائن بعد" + wra.get ()) ؛ }}} الفئة A {} ## نتيجة الإخراج هي:
لم يتم إعادة تدوير كائن بعد كائن@52E5376AA يدخل عملية جمع القمامة
يتم شرح النتيجة الأولى على النحو الوارد أعلاه. بعد جمع القمامة ، ستعود WRA.GET () NULL ، مما يشير إلى أنه يشير إلى أن الكائن قد دخل في عملية جمع القمامة. لذلك ، يتم تلخيص خصائص الاستشهادات الضعيفة على النحو التالي:
الضعف لا يغير توقيت جمع القمامة للكائن المرجعي القوي الأصلي. بمجرد أن يشير إلى أن الكائن ليس لديه أي كائن مرجعي قوي ، يدخل الكائن عملية جمع القمامة العادية.
لذلك ، بناءً على هذه الخاصية ، هناك سؤال: ما هي أهمية الضعف؟
سيناريوهات الاستخدام الرئيسية هي: هناك حاليًا مراجع قوية تشير إلى كائنات مرجعية قوية. في هذا الوقت ، نظرًا لاحتياجات العمل ، من الضروري زيادة الإشارات إلى هذا الكائن ، وفي الوقت نفسه ، لا يهدف إلى تغيير توقيت جمع القمامة لهذا المرجع. في هذا الوقت ، يلبي الضعف فقط الاحتياجات ويوجد عادة في بعض السيناريوهات مع دورات الحياة.
فيما يلي سيناريو لاستخدام الضعف في Android - الجمع بين الطبقات الداخلية الثابتة والضعف لحل مشكلة تسرب ذاكرة المعالج المحتملة في النشاط.
في النشاط ، نحتاج إلى إنشاء مؤشر ترابط جديد للحصول على البيانات واستخدام المعالج - طريقة SendMessage. هنا هو الرمز العام لهذه العملية:
يمتد النشاط الرئيسي للطبقة العامة النشاط {// ... private int page ؛ معالج المعالج الخاص = New Handler () {Override public void handlemessage (message msg) {if (msg.what == 1) {// ... page ++ ؛ } آخر { //... } }؛ } ؛ Override محمية void onCreate (backdle SaveInstancestate) {super.oncreate (SaveInstancestate) ؛ setContentView (r.layout.activity_main) ؛ // ... مؤشر ترابط جديد (جديد RunNable () {Override public void run () {// .. message msg = message.obtain () ؛ msg.what = 1 ؛ //msg.obj = xx ؛ handler.sendmessage (msg) ؛}}). start () ؛ // ...}}قم بتشغيل الرابط في Eclispe ، سترى رسالة تحذير: يجب أن تكون فئة المعالج ثابتة أو قد تحدث تسريبات ... انقر لعرض هذه المعلومات ، والتي تصف المشكلة في التفاصيل وتوفر حلًا موحيًا.
المشكلة: يضمن عدم التمسك بفئات المعالج إلى مرجع إلى كل منهج خارجي: يتم إعلان هذا المعالج على أنه فئة داخلية ، فقد يمنع الفئة الخارجية من جمع القمامة. إذا كان المعالج يستخدم looper أو messagequeue لمؤشر ترابط غير مؤشر الترابط الرئيسي ، فلا توجد مشكلة. إذا كان المعالج يستخدم looper أو messagequeue من الخيط الرئيسي ، فأنت بحاجة إلى إصلاح إعلان معالجك ، على النحو التالي: أعلن أن المعالج كطبقة ثابتة ؛ في الفئة الخارجية ، قم بتثبيت وضع ضعيف في الفئة الخارجية وتمرير هذا الكائن إلى معالجك عند إنشاء المعالج ؛ قم بإجراء جميع الإشارات إلى أعضاء الفئة الخارجية باستخدام كائن DepReference.
المعنى العام هو أنه يوصى بتحديد المعالج على أنه فئة ثابتة داخلية ، وتحديد إشارة إلى الضعف في هذه الفئة الداخلية الثابتة ، بسبب الإشارة إلى كائن النشاط الخارجي.
تحليل المشكلة:
النشاط له دورة حياته الخاصة. أثناء عملية تشغيل مؤشرات الترابط المفتوحة حديثًا في النشاط ، يجوز للمستخدم الضغط على المفتاح الخلفي أو أن النظام غير كافٍ للذاكرة ، وما إلى ذلك لإعادة تدوير هذا النشاط. نظرًا لأن المواضيع التي تم إطلاقها حديثًا في النشاط لن تتبع دورة النشاط نفسه ، أي عندما ينفذ النشاط ondestroy ، نظرًا لوجود مؤشرات الترابط ودليل معالج ، فإن النظام يأمل في الأصل إجراء استرداد الذاكرة لهذا النشاط ، لأن الفئة الداخلية غير الستنية تحمل مراجعًا إلى الفئات الخارجية ، وإدخال مشكلات في الذاكرة الممكنة.
لذلك ، عند استخدام معالج في النشاط ، من ناحية ، يجب تعريفه على أنه نموذج داخلي ثابت ، بحيث يمكن فصله عن الفئة الخارجية ولم يعد يحمل إشارات إلى الفئة الخارجية. في الوقت نفسه ، نظرًا لأن المعالجة في المعالج تحتاج عمومًا إلى الوصول إلى أو تعديل خصائص النشاط ، في هذا الوقت ، يجب تعريف الإشارة إلى هذا النشاط داخل المعالج حتى لا يؤثر على استرداد ذاكرة النشاط. في الوقت نفسه ، يمكن الوصول إلى خصائص النشاط في ظل الظروف العادية.
توصيات Google الرسمية هي:
يمتد النشاط الرئيسي للطبقة العامة النشاط {// ... private int page ؛ myhandler الخاص mmyhandler = new myhandler (هذا) ؛ الطبقة الثابتة الخاصة myhandler يمتد معالج {private preferference <MainActivity> wractivity ؛ MyHandler العامة (نشاط النشاط الرئيسي) {this.wractivity = new Deperference <MainActivity> (النشاط) ؛ } Override public void handlemessage (message msg) {if (wractivity.get () == null) {return ؛ } mactivity maictivity = wractivity.get () ؛ if (msg.what == 1) {// ... mactivity.page ++ ؛ } آخر {// ...}}} override void onCreate (bundle saveInstancestate) {super.oncreate (saveInstancestate) ؛ setContentView (r.layout.activity_main) ؛ // ... موضوع جديد (جديد Runnable () {Override public void run () {// .. message msg = message.obtain () ؛ msg.what = 1 ؛ //msg.obj = xx ؛ mmyHandler.SendMessage (msg) ؛}}). start () ؛ // ...}}بالنسبة إلى Softreference و DepReference ، هناك أيضًا مرجعية معلمة مُنشأة <T> ، وعندما يتم بالفعل جمع الكائن المشار إليه بواسطة softreference أو الضعف القمامة ، سيتم وضع مرجعه في المرجع. لاحظ أنه على النحو الوارد أعلاه ، عندما تُرجع طريقة GET () لإرجاع Softreference أو DepReference NULL ، فإنه يشير فقط إلى أن الكائن الذي يشير إليه قد دخل في عملية جمع القمامة ، وقد لا يكون الكائن قد تم جمعه في هذا الوقت. فقط بعد التأكيد على أنه تم جمع القمامة ، إذا كان المرجعية ، فسيتم وضع مرجعه في المرجع.
انظر مثال أدناه:
الفئة العامة المرجعية {public static void main (string [] args) {a a = new a () ؛ PreferReference <a> wra = new Preferference <a> (a) ؛ أ = خالية ؛ if (wra.get () == null) {system.out.println ("يدخل كائن عملية جمع القمامة") ؛ } آخر {system.out.println ("لم يتم إعادة تدوير كائن بعد" + wra.get ()) ؛ } // Garbage Collection System.gc () ؛ if (wra.get () == null) {system.out.println ("يدخل كائن عملية جمع القمامة") ؛ } آخر {system.out.println ("لم يتم إعادة تدوير كائن بعد" + wra.get ()) ؛ }}} class a {override void void finize () remable {super.finalize () ؛ System.out.println ("في نهاية") ؛ }} ## نتيجة الإخراج هي:
1 لم يتم إعادة تدوير كائن@46993aaa2 تم إعادة تدوير كائن 3 في النهاية
يتحقق هذا أيضًا من بيان "إدخال عملية جمع القمامة" المذكورة أعلاه. دعونا نلقي نظرة على قطعة من الكود مع مرجع:
الفئة العامة المرجعية {public static void main (string [] args) {a a = new a () ؛ ReferenceQueue <a> rq = new ReferenceQueue <a> () ؛ PreferReference <a> wra = new Preferference <a> (a ، rq) ؛ أ = خالية ؛ if (wra.get () == null) {system.out.println ("يدخل كائن عملية جمع القمامة") ؛ } آخر {system.out.println ("لم يتم إعادة تدوير كائن بعد" + wra.get ()) ؛ } system.out.println ("RQ item:" + rq.poll ()) ؛ // Garbage Collection System.gc () ؛ if (wra.get () == null) {system.out.println ("يدخل كائن عملية جمع القمامة") ؛ } آخر {system.out.println ("لم يتم إعادة تدوير كائن بعد" + wra.get ()) ؛ } /* try {thread.sleep (1000) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ } */ system.out.println ("RQ Item:" + rq.poll ()) ؛ }} class a {override protected void finize () rewrows {super.finalize () ؛ System.out.println ("في نهاية") ؛ }} ## نتيجة الإخراج هي:
لم يتم إعادة تدوير كائن بعد@302b2c81rq العنصر: كائن Nulla يدخل عملية جمع القمامة العنصر RQ: nullin a الانتهاء
وبالتالي ، يتم التحقق من أنه لم تتم إضافة "مراجع SoftReference أو Preferference التي تدخل فقط في عملية جمع القمامة إلى المرجعية".
الفئة العامة المرجعية {public static void main (string [] args) {a a = new a () ؛ ReferenceQueue <a> rq = new ReferenceQueue <a> () ؛ PreferReference <a> wra = new Preferference <a> (a ، rq) ؛ أ = خالية ؛ if (wra.get () == null) {system.out.println ("يدخل كائن عملية جمع القمامة") ؛ } آخر {system.out.println ("لم يتم إعادة تدوير كائن بعد" + wra.get ()) ؛ } system.out.println ("RQ item:" + rq.poll ()) ؛ // Garbage Collection System.gc () ؛ if (wra.get () == null) {system.out.println ("يدخل كائن عملية جمع القمامة") ؛ } آخر {system.out.println ("لم يتم إعادة تدوير كائن بعد" + wra.get ()) ؛ } جرب {thread.sleep (1) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ } system.out.println ("RQ item:" + rq.poll ()) ؛ }} class a {override protected void finize () rewrows {super.finalize () ؛ System.out.println ("في نهاية") ؛ }} ## نتيجة الإخراج هي:
لم يتم إعادة تدوير كائن بعد@6276e1dbrq البند: كائن nulla يدخل عملية جمع القمامة في عنصر نهائي: java.lang.ref.weakreference@645064f
هذا يؤكد البيان أعلاه.
4. phantomreference
بالمقارنة مع الإحسان أو الضعف ، تنعكس الاختلافات الرئيسية في الفانتومري في النقاط التالية:
1. فانتومري لا يحتوي على مُنشئ واحد فقط (مرجع T ، مرجعية <؟ super t> q) ، لذلك يجب استخدام الفانتومري مع مرجع ؛
2. بغض النظر عما إذا كانت هناك إشارة قوية إلى كائن المؤشر الذي يشير إلى الوهمية ، فإن طريقة GET () لإرجاع النتيجة الفارغة.
الفئة العامة المرجعية {public static void main (string [] args) {a a = new a () ؛ ReferenceQueue <a> rq = new ReferenceQueue <a> () ؛ phantomreference <a> pra = new phantomreference <a> (a ، rq) ؛ System.out.println ("pra.get ():" + pra.get ()) ؛ أ = خالية ؛ System.gc () ؛ حاول {thread.sleep (1) ؛ } catch (interruptedException e) {E.PrintStackTrace () ؛ } system.out.println ("RQ item:" + rq.poll ()) ؛ }} الفئة A {} ## نتيجة الإخراج هي:
pra.get (): nullrq البند: java.lang.ref.phantomreference@1da12fc0
thread.sleep (1) ؛ في وظائف التعليمات البرمجية كما هو الحال في المثال أعلاه ، وتأكد من تنفيذ مؤشر ترابط مجموعة القمامة. خلاف ذلك ، لن تتم إضافة الإشارات الافتراضية إلى كائن المؤشر الذي يدخل عملية جمع القمامة دون أن يتم جمع القمامة بالفعل إلى فانتومري.
مثل الضعف ، لا يغير الفانتومريان توقيت جمع القمامة لكائنه المشير. يمكن أن نستنتج أن وظيفة المرجعية تستخدم بشكل أساسي للاستماع إلى الإحسان/الضعف/الفصائل التي تشير إلى ما إذا كان الكائن قد تم جمع القمامة.
ما سبق هو المحتوى الكامل للتحليل الشامل لأنواع مرجع Java/Android والاستخدام الذي جلبه لك المحرر. آمل أن يكون ذلك مفيدًا لك ودعم wulin.com أكثر ~