تصحيح مجموعة القمامة ART

توضح هذه الصفحة كيفية تصحيح مشكلات صحة أداء مجموعة البيانات المهملة (GC) في Android Runtime (ART). وهو يشرح كيفية استخدام خيارات التحقق من GC، وتحديد الحلول لحالات فشل التحقق من GC، وقياس مشكلات أداء GC ومعالجتها.

للعمل مع ART، راجع الصفحات الموجودة في قسم ART وDalvik وتنسيق Dalvik القابل للتنفيذ . للحصول على مساعدة إضافية في التحقق من سلوك التطبيق، راجع التحقق من سلوك التطبيق في وقت تشغيل Android (ART) .

نظرة عامة على ART GC

لدى ART عدد قليل من خطط GC المختلفة التي تتكون من تشغيل جامعي القمامة المختلفين. بدءًا من Android 8 (Oreo)، فإن الخطة الافتراضية هي النسخ المتزامن (CC). خطة GC الأخرى هي Concurrent Mark Sweep (CMS).

بعض الخصائص الرئيسية للنسخ المتزامن GC هي:

  • يتيح CC استخدام مُخصص مؤشر النتوء المسمى RegionTLAB. يؤدي هذا إلى تخصيص مخزن مؤقت لتخصيص مؤشر الترابط المحلي (TLAB) لكل مؤشر ترابط تطبيق، والذي يمكنه بعد ذلك تخصيص الكائنات من TLAB الخاص به عن طريق رفع المؤشر "العلوي"، دون أي مزامنة.
  • يقوم CC بإلغاء تجزئة الكومة عن طريق نسخ الكائنات بشكل متزامن دون إيقاف سلاسل عمليات التطبيق مؤقتًا. يتم تحقيق ذلك بمساعدة حاجز القراءة الذي يعترض القراءات المرجعية من الكومة، دون الحاجة إلى أي تدخل من مطور التطبيق.
  • لدى GC وقفة صغيرة واحدة فقط، والتي تكون ثابتة في الوقت المناسب فيما يتعلق بحجم الكومة.
  • يمتد CC ليكون GC للأجيال في Android 10 والإصدارات الأحدث. فهو يتيح جمع الأشياء الصغيرة، والتي غالبًا ما يتعذر الوصول إليها بسرعة إلى حد ما، مع القليل من الجهد. يساعد هذا من خلال زيادة إنتاجية GC وتأخير الحاجة إلى إجراء GC كامل الكومة بشكل كبير.

GC الآخر الذي لا يزال ART يدعمه هو CMS. يدعم GC هذا أيضًا الضغط، ولكن ليس بشكل متزامن. يتم تجنب الضغط حتى ينتقل التطبيق إلى الخلفية، وفي ذلك الوقت يتم إيقاف سلاسل رسائل التطبيق مؤقتًا لإجراء الضغط. يصبح الضغط ضروريًا أيضًا عند فشل تخصيص الكائن بسبب التجزئة. في هذه الحالة، من المحتمل أن يصبح التطبيق غير مستجيب لبعض الوقت.

نظرًا لأن CMS نادرًا ما يتم ضغطه، وبالتالي قد لا تكون الكائنات الحرة متجاورة، فإنه يستخدم مخصصًا قائمًا على القائمة الحرة يسمى RosAlloc. لديها تكلفة تخصيص أعلى مقارنة بـ RegionTLAB. أخيرًا، بسبب التجزئة الداخلية، يمكن أن يكون استخدام الذاكرة لكومة Java أعلى بالنسبة لنظام إدارة المحتوى (CMS) مقارنةً بـ CC.

خيارات التحقق والأداء من GC

تغيير نوع جي سي

يمكن لمصنعي المعدات الأصلية تغيير نوع GC. تتضمن عملية التغيير تعيين متغير البيئة ART_USE_READ_BARRIER في وقت الإنشاء. القيمة الافتراضية هي true، مما يمكّن أداة تجميع CC من استخدام حاجز القراءة. بالنسبة لنظام إدارة المحتوى (CMS)، يجب تعيين هذا المتغير بشكل صريح إلى "خطأ".

افتراضيًا، يعمل مُجمع CC في وضع الأجيال في Android 10 والإصدارات الأحدث. لتعطيل وضع الأجيال، يمكن استخدام وسيطة سطر الأوامر -Xgc:nogenerational_cc . وبدلاً من ذلك، يمكن تعيين خاصية النظام على النحو التالي:

adb shell setprop dalvik.vm.gctype nogenerational_cc
يعمل مُجمع CMS دائمًا في وضع الأجيال.

التحقق من الكومة

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

  • في حالة التمكين، يقوم [no]preverify بإجراء التحقق من الكومة قبل بدء تشغيل GC.
  • في حالة التمكين، [no]presweepingverify بإجراء التحقق من الكومة قبل بدء عملية المسح لمجمع البيانات المهملة.
  • إذا تم تمكينه، فإن [no]postverify يقوم بإجراء التحقق من الكومة بعد انتهاء GC من عملية المسح.
  • [no]preverify_rosalloc و [no]postsweepingverify_rosalloc و [no]postverify_rosalloc هي خيارات GC إضافية تتحقق فقط من حالة المحاسبة الداخلية لـ RosAlloc. لذلك، فهي قابلة للتطبيق فقط مع مُجمع CMS، الذي يستخدم مُخصص RosAlloc. الأشياء الرئيسية التي تم التحقق منها هي أن القيم السحرية تتطابق مع الثوابت المتوقعة، ويتم تسجيل جميع كتل الذاكرة المجانية في خريطة free_page_runs_ .

أداء

هناك أداتان رئيسيتان لقياس أداء GC، مقالب توقيت GC وSystrace. هناك أيضًا إصدار متقدم من Systrace يسمى Perfetto. تتمثل الطريقة المرئية لقياس مشكلات أداء GC في استخدام Systrace وPerfetto لتحديد GCs التي تسبب توقفًا مؤقتًا طويلًا أو تستبق سلاسل عمليات التطبيق. على الرغم من أن ART GC قد تحسن بشكل ملحوظ مع مرور الوقت، إلا أن سلوك المتحول السيئ، مثل التخصيص المفرط، لا يزال من الممكن أن يسبب مشاكل في الأداء

استراتيجية التحصيل

يتم تجميع CC GC إما عن طريق تشغيل GC صغير أو GC كامل الكومة. ومن الناحية المثالية، يتم تشغيل GC الشاب في كثير من الأحيان. يقوم GC بمجموعات CC الصغيرة حتى تصبح الإنتاجية (المحسوبة بالبايتات المحررة/الثانية من مدة GC) لدورة التجميع المنتهية للتو أقل من متوسط ​​الإنتاجية لمجموعات CC ذات الكومة الكاملة. عند حدوث ذلك، يتم اختيار CC الكومة الكاملة لـ GC المتزامن التالي بدلاً من CC الصغيرة. بعد اكتمال مجموعة الكومة الكاملة، يتم تحويل GC التالي مرة أخرى إلى CC الصغيرة. أحد العوامل الرئيسية التي تجعل هذه الإستراتيجية تعمل هو أن CC الصغيرة لا تقوم بضبط حد مساحة الكومة بعد اكتمالها. يؤدي هذا إلى حدوث CC شاب أكثر فأكثر حتى تصبح الإنتاجية أقل من CC الكومة الكاملة، مما يؤدي في النهاية إلى زيادة الكومة.

استخدم SIGQUIT للحصول على معلومات أداء GC

للحصول على توقيتات أداء GC للتطبيقات، أرسل SIGQUIT إلى التطبيقات قيد التشغيل بالفعل أو قم بتمرير -XX:DumpGCPerformanceOnShutdown إلى dalvikvm عند بدء تشغيل برنامج سطر الأوامر. عندما يحصل أحد التطبيقات على إشارة طلب ANR ( SIGQUIT )، فإنه يتخلص من المعلومات المتعلقة بأقفاله ومكدسات الخيوط وأداء GC.

للحصول على تفريغ توقيت GC، استخدم:

adb shell kill -s QUIT PID

يؤدي هذا إلى إنشاء ملف (مع التاريخ والوقت في الاسم مثل anr_2020-07-13-19-23-39-817) في /data/anr/ . يحتوي هذا الملف على بعض عمليات تفريغ ANR بالإضافة إلى توقيتات GC. يمكنك تحديد توقيتات GC من خلال البحث عن تفريغ توقيتات Gc التراكمية . تُظهر هذه التوقيتات بعض الأشياء التي قد تكون ذات أهمية، بما في ذلك معلومات الرسم البياني لكل مراحل وتوقفات مؤقتة لكل نوع GC. عادة ما تكون فترات التوقف المؤقت أكثر أهمية للنظر إليها. على سبيل المثال:

young concurrent copying paused:	Sum: 5.491ms 99% C.I. 1.464ms-2.133ms Avg: 1.830ms Max: 2.133ms

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

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

suspend all histogram:	Sum: 1.513ms 99% C.I. 3us-546.560us Avg: 47.281us Max: 601us

هناك مجالات أخرى ذات أهمية، بما في ذلك إجمالي الوقت المستغرق وإنتاجية GC. أمثلة:

Total time spent in GC: 502.251ms
Mean GC size throughput: 92MB/s
Mean GC object throughput: 1.54702e+06 objects/s

فيما يلي مثال لكيفية تفريغ توقيتات GC لتطبيق قيد التشغيل بالفعل:

adb shell kill -s QUIT PID
adb pull /data/anr/anr_2020-07-13-19-23-39-817

في هذه المرحلة، تكون توقيتات GC داخل anr_2020-07-13-19-23-39-817 . إليك مثال على الإخراج من خرائط Google:

Start Dumping histograms for 2195 iterations for concurrent copying
MarkingPhase:   Sum: 258.127s 99% C.I. 58.854ms-352.575ms Avg: 117.651ms Max: 641.940ms
ScanCardsForSpace:      Sum: 85.966s 99% C.I. 15.121ms-112.080ms Avg: 39.164ms Max: 662.555ms
ScanImmuneSpaces:       Sum: 79.066s 99% C.I. 7.614ms-57.658ms Avg: 18.014ms Max: 546.276ms
ProcessMarkStack:       Sum: 49.308s 99% C.I. 6.439ms-81.640ms Avg: 22.464ms Max: 638.448ms
ClearFromSpace: Sum: 35.068s 99% C.I. 6.522ms-40.040ms Avg: 15.976ms Max: 633.665ms
SweepSystemWeaks:       Sum: 14.209s 99% C.I. 3.224ms-15.210ms Avg: 6.473ms Max: 201.738ms
CaptureThreadRootsForMarking:   Sum: 11.067s 99% C.I. 0.835ms-13.902ms Avg: 5.044ms Max: 25.565ms
VisitConcurrentRoots:   Sum: 8.588s 99% C.I. 1.260ms-8.547ms Avg: 1.956ms Max: 231.593ms
ProcessReferences:      Sum: 7.868s 99% C.I. 0.002ms-8.336ms Avg: 1.792ms Max: 17.376ms
EnqueueFinalizerReferences:     Sum: 3.976s 99% C.I. 0.691ms-8.005ms Avg: 1.811ms Max: 16.540ms
GrayAllDirtyImmuneObjects:      Sum: 3.721s 99% C.I. 0.622ms-6.702ms Avg: 1.695ms Max: 14.893ms
SweepLargeObjects:      Sum: 3.202s 99% C.I. 0.032ms-6.388ms Avg: 1.458ms Max: 549.851ms
FlipOtherThreads:       Sum: 2.265s 99% C.I. 0.487ms-3.702ms Avg: 1.031ms Max: 6.327ms
VisitNonThreadRoots:    Sum: 1.883s 99% C.I. 45us-3207.333us Avg: 429.210us Max: 27524us
InitializePhase:        Sum: 1.624s 99% C.I. 231.171us-2751.250us Avg: 740.220us Max: 6961us
ForwardSoftReferences:  Sum: 1.071s 99% C.I. 215.113us-2175.625us Avg: 488.362us Max: 7441us
ReclaimPhase:   Sum: 490.854ms 99% C.I. 32.029us-6373.807us Avg: 223.623us Max: 362851us
EmptyRBMarkBitStack:    Sum: 479.736ms 99% C.I. 11us-3202.500us Avg: 218.558us Max: 13652us
CopyingPhase:   Sum: 399.163ms 99% C.I. 24us-4602.500us Avg: 181.851us Max: 22865us
ThreadListFlip: Sum: 295.609ms 99% C.I. 15us-2134.999us Avg: 134.673us Max: 13578us
ResumeRunnableThreads:  Sum: 238.329ms 99% C.I. 5us-2351.250us Avg: 108.578us Max: 10539us
ResumeOtherThreads:     Sum: 207.915ms 99% C.I. 1.072us-3602.499us Avg: 94.722us Max: 14179us
RecordFree:     Sum: 188.009ms 99% C.I. 64us-312.812us Avg: 85.653us Max: 2709us
MarkZygoteLargeObjects: Sum: 133.301ms 99% C.I. 12us-734.999us Avg: 60.729us Max: 10169us
MarkStackAsLive:        Sum: 127.554ms 99% C.I. 13us-417.083us Avg: 58.111us Max: 1728us
FlipThreadRoots:        Sum: 126.119ms 99% C.I. 1.028us-3202.499us Avg: 57.457us Max: 11412us
SweepAllocSpace:        Sum: 117.761ms 99% C.I. 24us-400.624us Avg: 53.649us Max: 1541us
SwapBitmaps:    Sum: 56.301ms 99% C.I. 10us-125.312us Avg: 25.649us Max: 1475us
(Paused)GrayAllNewlyDirtyImmuneObjects: Sum: 33.047ms 99% C.I. 9us-49.931us Avg: 15.055us Max: 72us
(Paused)SetFromSpace:   Sum: 11.651ms 99% C.I. 2us-49.772us Avg: 5.307us Max: 71us
(Paused)FlipCallback:   Sum: 7.693ms 99% C.I. 2us-32us Avg: 3.504us Max: 32us
(Paused)ClearCards:     Sum: 6.371ms 99% C.I. 250ns-49753ns Avg: 207ns Max: 188000ns
Sweep:  Sum: 5.793ms 99% C.I. 1us-49.818us Avg: 2.639us Max: 93us
UnBindBitmaps:  Sum: 5.255ms 99% C.I. 1us-31us Avg: 2.394us Max: 31us
Done Dumping histograms
concurrent copying paused:      Sum: 315.249ms 99% C.I. 49us-1378.125us Avg: 143.621us Max: 7722us
concurrent copying freed-bytes: Avg: 34MB Max: 54MB Min: 2062KB
Freed-bytes histogram: 0:4,5120:5,10240:19,15360:69,20480:167,25600:364,30720:529,35840:405,40960:284,46080:311,51200:38
concurrent copying total time: 569.947s mean time: 259.657ms
concurrent copying freed: 1453160493 objects with total size 74GB
concurrent copying throughput: 2.54964e+06/s / 134MB/s  per cpu-time: 157655668/s / 150MB/s
Average major GC reclaim bytes ratio 0.486928 over 2195 GC cycles
Average major GC copied live bytes ratio 0.0894662 over 2199 major GCs
Cumulative bytes moved 6586367960
Cumulative objects moved 127490240
Peak regions allocated 376 (94MB) / 2048 (512MB)
Start Dumping histograms for 685 iterations for young concurrent copying
ScanCardsForSpace:      Sum: 26.288s 99% C.I. 8.617ms-77.759ms Avg: 38.377ms Max: 432.991ms
ProcessMarkStack:       Sum: 21.829s 99% C.I. 2.116ms-71.119ms Avg: 31.868ms Max: 98.679ms
ClearFromSpace: Sum: 19.420s 99% C.I. 5.480ms-50.293ms Avg: 28.351ms Max: 507.330ms
ScanImmuneSpaces:       Sum: 9.968s 99% C.I. 8.155ms-30.639ms Avg: 14.552ms Max: 46.676ms
SweepSystemWeaks:       Sum: 6.741s 99% C.I. 3.655ms-14.715ms Avg: 9.841ms Max: 22.142ms
GrayAllDirtyImmuneObjects:      Sum: 4.466s 99% C.I. 0.584ms-14.315ms Avg: 6.519ms Max: 24.355ms
FlipOtherThreads:       Sum: 3.672s 99% C.I. 0.631ms-16.630ms Avg: 5.361ms Max: 18.513ms
ProcessReferences:      Sum: 2.806s 99% C.I. 0.001ms-9.459ms Avg: 2.048ms Max: 11.951ms
EnqueueFinalizerReferences:     Sum: 1.857s 99% C.I. 0.424ms-8.609ms Avg: 2.711ms Max: 24.063ms
VisitConcurrentRoots:   Sum: 1.094s 99% C.I. 1.306ms-5.357ms Avg: 1.598ms Max: 6.831ms
SweepArray:     Sum: 711.032ms 99% C.I. 0.022ms-3.502ms Avg: 1.038ms Max: 7.307ms
InitializePhase:        Sum: 667.346ms 99% C.I. 303us-2643.749us Avg: 974.227us Max: 3199us
VisitNonThreadRoots:    Sum: 388.145ms 99% C.I. 103.911us-1385.833us Avg: 566.635us Max: 5374us
ThreadListFlip: Sum: 202.730ms 99% C.I. 18us-2414.999us Avg: 295.956us Max: 6780us
EmptyRBMarkBitStack:    Sum: 132.934ms 99% C.I. 8us-1757.499us Avg: 194.064us Max: 8495us
ResumeRunnableThreads:  Sum: 109.593ms 99% C.I. 6us-4719.999us Avg: 159.989us Max: 11106us
ResumeOtherThreads:     Sum: 86.733ms 99% C.I. 3us-4114.999us Avg: 126.617us Max: 19332us
ForwardSoftReferences:  Sum: 69.686ms 99% C.I. 14us-2014.999us Avg: 101.731us Max: 4723us
RecordFree:     Sum: 58.889ms 99% C.I. 0.500us-185.833us Avg: 42.984us Max: 769us
FlipThreadRoots:        Sum: 58.540ms 99% C.I. 1.034us-4314.999us Avg: 85.459us Max: 10224us
CopyingPhase:   Sum: 52.227ms 99% C.I. 26us-728.749us Avg: 76.243us Max: 2060us
ReclaimPhase:   Sum: 37.207ms 99% C.I. 7us-2322.499us Avg: 54.316us Max: 3826us
(Paused)GrayAllNewlyDirtyImmuneObjects: Sum: 23.859ms 99% C.I. 11us-98.917us Avg: 34.830us Max: 128us
FreeList:       Sum: 20.376ms 99% C.I. 2us-188.875us Avg: 29.573us Max: 998us
MarkZygoteLargeObjects: Sum: 18.970ms 99% C.I. 4us-115.749us Avg: 27.693us Max: 122us
(Paused)SetFromSpace:   Sum: 12.331ms 99% C.I. 3us-94.226us Avg: 18.001us Max: 109us
SwapBitmaps:    Sum: 11.761ms 99% C.I. 5us-49.968us Avg: 17.169us Max: 67us
ResetStack:     Sum: 4.317ms 99% C.I. 1us-64.374us Avg: 6.302us Max: 190us
UnBindBitmaps:  Sum: 3.803ms 99% C.I. 4us-49.822us Avg: 5.551us Max: 70us
(Paused)ClearCards:     Sum: 3.336ms 99% C.I. 250ns-7000ns Avg: 347ns Max: 7000ns
(Paused)FlipCallback:   Sum: 3.082ms 99% C.I. 1us-30us Avg: 4.499us Max: 30us
Done Dumping histograms
young concurrent copying paused:        Sum: 229.314ms 99% C.I. 37us-2287.499us Avg: 334.764us Max: 6850us
young concurrent copying freed-bytes: Avg: 44MB Max: 50MB Min: 9132KB
Freed-bytes histogram: 5120:1,15360:1,20480:6,25600:1,30720:1,35840:9,40960:235,46080:427,51200:4
young concurrent copying total time: 100.823s mean time: 147.187ms
young concurrent copying freed: 519927309 objects with total size 30GB
young concurrent copying throughput: 5.15683e+06/s / 304MB/s  per cpu-time: 333152554/s / 317MB/s
Average minor GC reclaim bytes ratio 0.52381 over 685 GC cycles
Average minor GC copied live bytes ratio 0.0512109 over 685 minor GCs
Cumulative bytes moved 1542000944
Cumulative objects moved 28393168
Peak regions allocated 376 (94MB) / 2048 (512MB)
Total time spent in GC: 670.771s
Mean GC size throughput: 159MB/s per cpu-time: 177MB/s
Mean GC object throughput: 2.94152e+06 objects/s
Total number of allocations 1974199562
Total bytes allocated 104GB
Total bytes freed 104GB
Free memory 10MB
Free memory until GC 10MB
Free memory until OOME 442MB
Total memory 80MB
Max memory 512MB
Zygote space size 2780KB
Total mutator paused time: 544.563ms
Total time waiting for GC to complete: 117.494ms
Total GC count: 2880
Total GC time: 670.771s
Total blocking GC count: 1
Total blocking GC time: 86.373ms
Histogram of GC count per 10000 ms: 0:259879,1:2828,2:24,3:1
Histogram of blocking GC count per 10000 ms: 0:262731,1:1
Native bytes total: 30599192 registered: 8947416
Total native bytes at last GC: 30344912

أدوات لتحليل مشاكل صحة GC

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

CheckJNI

CheckJNI هو وضع يضيف عمليات فحص JNI للتحقق من سلوك التطبيق؛ ولا يتم تمكينها افتراضيًا لأسباب تتعلق بالأداء. تكتشف عمليات التحقق بعض الأخطاء التي قد تتسبب في تلف الكومة، مثل استخدام مراجع محلية وعامة غير صالحة/قديمة. لتمكين CheckJNI:

adb shell setprop dalvik.vm.checkjni true

يعد وضع forcecopy الخاص بـ CheckJNI مفيدًا في اكتشاف عمليات الكتابة بعد نهاية مناطق المصفوفة. عند التمكين، يؤدي forcecopy إلى قيام وظائف JNI للوصول إلى المصفوفة بإرجاع نسخ ذات مناطق حمراء. المنطقة الحمراء هي منطقة في نهاية/بداية المؤشر الذي تم إرجاعه ولها قيمة خاصة، والتي يتم التحقق منها عند تحرير المصفوفة. إذا كانت القيم الموجودة في المنطقة الحمراء لا تتطابق مع ما هو متوقع، فقد حدث تجاوز أو نقص في المخزن المؤقت. يؤدي هذا إلى إحباط CheckJNI. لتمكين وضع النسخ القسري:

adb shell setprop dalvik.vm.jniopts forcecopy

مثال على الخطأ الذي يجب على CheckJNI اكتشافه هو الكتابة بعد نهاية المصفوفة التي تم الحصول عليها من GetPrimitiveArrayCritical . قد تؤدي هذه العملية إلى إتلاف كومة Java. إذا كانت الكتابة ضمن منطقة المنطقة الحمراء لـ CheckJNI، فسيكتشف CheckJNI المشكلة عند استدعاء ReleasePrimitiveArrayCritical المقابل. وإلا، فإن الكتابة تؤدي إلى إتلاف بعض الكائنات العشوائية في كومة Java ويمكن أن تتسبب في تعطل GC في المستقبل. إذا كانت الذاكرة التالفة عبارة عن حقل مرجعي، فقد يلتقط GC الخطأ ويطبع الخطأ الذي تمت محاولته وضع علامة على <ptr> غير متضمن في أي مسافات .

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

مثال الجذر غير صالح

في حالة كون الكائن جذرًا غير صالح، فإنه يطبع بعض المعلومات المفيدة: art E 5955 5955 art/runtime/gc/collector/mark_sweep.cc:383] Tried to mark 0x2 not contained by any spaces

art E  5955  5955 art/runtime/gc/collector/mark_sweep.cc:384] Attempting see if
it's a bad root
art E  5955  5955 art/runtime/gc/collector/mark_sweep.cc:485] Found invalid
root: 0x2
art E  5955  5955 art/runtime/gc/collector/mark_sweep.cc:486]
Type=RootJavaFrame thread_id=1 location=Visiting method 'java.lang.Object
com.google.gwt.collections.JavaReadableJsArray.get(int)' at dex PC 0x0002
(native PC 0xf19609d9) vreg=1

في هذه الحالة، vreg=1 داخل com.google.gwt.collections.JavaReadableJsArray.get من المفترض أن يحتوي على مرجع كومة، ولكنه يحتوي على مؤشر غير صالح للعنوان 0x2 . هذا جذر غير صالح. لتصحيح هذه المشكلة، استخدم oatdump على ملف الشوفان وانظر إلى الطريقة ذات الجذر غير الصالح. في هذه الحالة، تبين أن الخطأ هو خطأ في برنامج التحويل البرمجي في الواجهة الخلفية لـ x86. إليك قائمة التغييرات التي أصلحت المشكلة: https://android-review.googlesource.com/#/c/133932/

مثال على كائن تالف

إذا لم يكن الكائن جذرًا، فسيكون الإخراج مشابهًا للمطبوعات التالية:

01-15 12:38:00.196  1217  1238 E art     : Attempting see if it's a bad root
01-15 12:38:00.196  1217  1238 F art     :
art/runtime/gc/collector/mark_sweep.cc:381] Can't mark invalid object

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