هناك طريقة في سلاسل الرسائل يتم استدعاؤها بشكل متكرر من قبل الجميع، وهي ThreadLocal. ومع ذلك، سيواجه ThreadLocal أيضًا مشكلات أكثر صعوبة في معالجة الذاكرة، وسيحدث دائمًا بعض تسرب الذاكرة. ستستخدم هذه المقالة مثالًا للتسرب لتحليله للجميع، وستساعدك أيضًا على فهم بعض مواقف التسرب، واقتراح حلول ThreadLocal المقابلة.
1. أمثلة التسرب
إدخال الطبقة الداخلية الثابتة لـ ThreadLocalMap:
يمتد إدخال الفئة الثابتة WeakReference<ThreadLocal<?>> { /** القيمة المرتبطة بـ ThreadLocal هذا */ قيمة الكائن؛ إدخال(ThreadLocal<?> k, Object v) { سوبر (ك)؛ القيمة = الخامس؛ } }
يستخدم ThreadLocalMap إدخال فئة داخلية ثابتة لتنفيذ تخزين <k, v>، ويرث الإدخال فئة WeakReference، لذا فإن المفتاح في ThreadLocalMap هو في الواقع مرجع ضعيف لـ ThreadLocal.
على وجه التحديد، لأن ThreadLocalMap يستخدم المرجع الضعيف لـ ThreadLocal كمفتاح، عندما لا يكون لدى ThreadLocal مرجع خارجي قوي، سيكون GC. في هذا الوقت، سيظهر إدخال بمفتاح فارغ في ThreadLocalMap. بالطبع، لن يتم الوصول إلى قيمة هذا الإدخال أبدًا.
في هذه الحالة، إذا لم ينته مؤشر ترابط العمل الحالي، فسيتم الرجوع بقوة إلى القيمة ذات المفتاح الفارغ بواسطة Entry، ويتم الإشارة إلى الإدخال بقوة بواسطة ThreadLocalMap لمؤشر الترابط الحالي، مما يتسبب في عدم GCed لهذه القيمة أبدًا، مما يتسبب في حدوث ذاكرة تسريب.
2. الحل
يمكن لطرق CleanSomeSlots() و expungeStaleEntry() الخاصة بـ ThreadLocalMap مسح القيم باستخدام مفاتيح فارغة. في طرق set() وget() وremove() الخاصة بـ ThreadLocal، سيتم استدعاء cleanSomeSlots() أو expungeStaleEntry() لمسح جميع القيم باستخدام المفاتيح الفارغة في ThreadLocalMap.
ما ورد أعلاه هو الحل لمشكلة تسرب ذاكرة Java ThreadLocal. بالطبع، هذا لا يمكن أن يلعب سوى دورًا معينًا في تسرب الذاكرة، فهو مجرد نوع من الوضوح وليس هناك ما يضمن عدم حدوثه .