Gỡ lỗi bộ sưu tập rác ART

Trang này mô tả cách gỡ lỗi các vấn đề về hiệu suất và tính chính xác của bộ sưu tập rác (GC) của Android Runtime (ART). Nó giải thích cách sử dụng các tùy chọn xác minh GC, xác định các giải pháp cho các lỗi xác minh GC cũng như đo lường và giải quyết các vấn đề về hiệu suất của GC.

Để làm việc với ART, hãy xem các trang trong phần ART và Dalvik này cũng như định dạng Dalvik Executable . Để được trợ giúp thêm trong việc xác minh hành vi ứng dụng, hãy xem Xác minh hành vi ứng dụng trên thời gian chạy Android (ART) .

Tổng quan về ART GC

ART có một số gói GC khác nhau bao gồm việc chạy các trình thu gom rác khác nhau. Bắt đầu với Android 8 (Oreo), gói mặc định là Sao chép đồng thời (CC). Kế hoạch GC khác là Quét đánh dấu đồng thời (CMS).

Một số đặc điểm chính của GC sao chép đồng thời là:

  • CC cho phép sử dụng bộ cấp phát con trỏ va chạm có tên là RegionTLAB. Điều này phân bổ bộ đệm phân bổ cục bộ theo luồng (TLAB) cho từng luồng ứng dụng, sau đó có thể phân bổ các đối tượng ra khỏi TLAB của nó bằng cách chạm vào con trỏ "trên cùng" mà không cần bất kỳ đồng bộ hóa nào.
  • CC thực hiện chống phân mảnh vùng heap bằng cách sao chép đồng thời các đối tượng mà không tạm dừng các luồng ứng dụng. Điều này đạt được nhờ sự trợ giúp của một rào cản đọc nhằm chặn các lần đọc tham chiếu từ vùng heap mà không cần bất kỳ sự can thiệp nào từ nhà phát triển ứng dụng.
  • GC chỉ có một khoảng dừng nhỏ, không đổi theo thời gian liên quan đến kích thước heap.
  • CC mở rộng thành GC thế hệ trong Android 10 trở lên. Nó cho phép thu thập các đồ vật trẻ, thường không thể tiếp cận được khá nhanh chóng mà không tốn nhiều công sức. Điều này giúp tăng thông lượng GC và trì hoãn đáng kể nhu cầu thực hiện GC toàn vùng.

GC khác mà ART vẫn hỗ trợ là CMS. GC này cũng hỗ trợ nén nhưng không đồng thời. Việc nén được tránh cho đến khi ứng dụng chạy ở chế độ nền, lúc đó các luồng ứng dụng sẽ tạm dừng để thực hiện nén. Việc nén cũng trở nên cần thiết khi việc phân bổ đối tượng không thành công do bị phân mảnh. Trong trường hợp này, ứng dụng có thể không phản hồi trong một thời gian.

Vì CMS hiếm khi thu gọn và do đó các đối tượng tự do có thể không liền kề nhau nên nó sử dụng bộ cấp phát dựa trên danh sách tự do có tên là RosAlloc. Nó có chi phí phân bổ cao hơn so với RegionTLAB. Cuối cùng, do sự phân mảnh bên trong nên mức sử dụng bộ nhớ cho vùng heap Java của CMS có thể cao hơn CC.

Tùy chọn hiệu suất và xác minh GC

Thay đổi loại GC

OEM có thể thay đổi loại GC. Quá trình thay đổi bao gồm việc đặt biến môi trường ART_USE_READ_BARRIER tại thời điểm xây dựng. Giá trị mặc định là true, cho phép bộ thu CC khi nó sử dụng rào cản đọc. Đối với CMS, biến này phải được đặt rõ ràng thành false.

Theo mặc định, trình thu thập CC chạy ở chế độ thế hệ trong Android 10 trở lên. Để tắt chế độ thế hệ, có thể sử dụng đối số dòng lệnh -Xgc:nogenerational_cc . Ngoài ra, thuộc tính hệ thống có thể được đặt như sau:

adb shell setprop dalvik.vm.gctype nogenerational_cc
Trình thu thập CMS luôn chạy ở chế độ thế hệ.

Xác minh đống

Xác minh vùng heap có lẽ là tùy chọn GC hữu ích nhất để gỡ lỗi các lỗi liên quan đến GC hoặc lỗi vùng heap. Việc kích hoạt xác minh vùng heap khiến GC kiểm tra tính chính xác của vùng heap tại một số điểm trong quá trình thu gom rác. Xác minh vùng heap chia sẻ các tùy chọn tương tự như các tùy chọn thay đổi loại GC. Nếu được bật, xác minh vùng heap sẽ xác minh gốc và đảm bảo rằng các đối tượng có thể truy cập chỉ tham chiếu đến các đối tượng có thể truy cập khác. Xác minh GC được bật bằng cách chuyển các giá trị -Xgc sau:

  • Nếu được bật, [no]preverify sẽ thực hiện xác minh vùng nhớ khối xếp trước khi khởi động GC.
  • Nếu được bật, [no]presweepingverify sẽ thực hiện xác minh vùng nhớ heap trước khi bắt đầu quá trình quét trình thu gom rác.
  • Nếu được bật, [no]postverify sẽ thực hiện xác minh vùng nhớ khối xếp sau khi GC quét xong.
  • [no]preverify_rosalloc , [no]postsweepingverify_rosalloc[no]postverify_rosalloc là các tùy chọn GC bổ sung chỉ xác minh trạng thái kế toán nội bộ của RosAlloc. Do đó, chúng chỉ có thể áp dụng được với trình thu thập CMS sử dụng bộ cấp phát RosAlloc. Điều chính được xác minh là các giá trị ma thuật khớp với các hằng số dự kiến ​​và các khối bộ nhớ trống đều được đăng ký trong bản đồ free_page_runs_ .

Hiệu suất

Có hai công cụ chính để đo hiệu suất GC, kết xuất thời gian GC và Systrace. Ngoài ra còn có một phiên bản nâng cao của Systrace, được gọi là Perfetto. Cách trực quan để đo lường các vấn đề về hiệu suất của GC là sử dụng Systrace và Perfetto để xác định GC nào đang gây ra tình trạng tạm dừng kéo dài hoặc chiếm quyền ưu tiên các luồng ứng dụng. Mặc dù ART GC đã được cải thiện đáng kể theo thời gian, hành vi xấu của trình biến đổi, chẳng hạn như phân bổ quá mức, vẫn có thể gây ra vấn đề về hiệu suất

Chiến lược thu thập

CC GC thu thập bằng cách chạy GC trẻ hoặc GC đầy đủ. Lý tưởng nhất là GC trẻ được chạy thường xuyên hơn. GC thực hiện các bộ sưu tập CC trẻ cho đến khi thông lượng (được tính bằng byte giải phóng/giây của thời lượng GC) của chu kỳ thu thập vừa hoàn thành nhỏ hơn thông lượng trung bình của các bộ sưu tập CC đầy đủ heap. Khi điều này xảy ra, CC đầy đủ được chọn cho GC đồng thời tiếp theo thay vì CC trẻ. Sau khi quá trình thu thập toàn bộ heap hoàn tất, GC tiếp theo sẽ được chuyển trở lại CC trẻ. Một yếu tố quan trọng giúp chiến lược này hoạt động là CC non không điều chỉnh giới hạn dấu chân vùng lưu trữ sau khi hoàn thành. Điều này làm cho CC non xảy ra ngày càng thường xuyên hơn cho đến khi thông lượng thấp hơn CC toàn bộ đống, cuối cùng dẫn đến việc tăng trưởng vùng heap.

Sử dụng SIGQUIT để nhận thông tin hiệu suất GC

Để nhận thời gian hiệu suất GC cho ứng dụng, hãy gửi SIGQUIT tới các ứng dụng đang chạy hoặc chuyển -XX:DumpGCPerformanceOnShutdown tới dalvikvm khi bắt đầu chương trình dòng lệnh. Khi một ứng dụng nhận được tín hiệu yêu cầu ANR ( SIGQUIT ), ứng dụng đó sẽ loại bỏ thông tin liên quan đến khóa, ngăn xếp luồng và hiệu suất GC.

Để có được kết xuất thời gian GC, hãy sử dụng:

adb shell kill -s QUIT PID

Thao tác này sẽ tạo một tệp (có ngày và giờ trong tên, chẳng hạn như anr_2020-07-13-19-23-39-817) trong /data/anr/ . Tệp này chứa một số kết xuất ANR cũng như thời gian GC. Bạn có thể xác định thời gian GC bằng cách tìm kiếm thời gian Gc tích lũy Dumping . Những khoảng thời gian này hiển thị một số thông tin có thể đáng quan tâm, bao gồm thông tin biểu đồ cho các giai đoạn và khoảng dừng của từng loại GC. Việc tạm dừng thường quan trọng hơn để xem xét. Ví dụ:

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

Điều này cho thấy thời gian tạm dừng trung bình là 1,83 mili giây, đủ thấp để không gây ra hiện tượng bỏ lỡ khung hình trong hầu hết các ứng dụng và không phải là điều đáng lo ngại.

Một lĩnh vực quan tâm khác là thời gian tạm dừng, đo lường khoảng thời gian một luồng đạt đến điểm tạm dừng sau khi GC yêu cầu nó tạm dừng. Thời gian này được bao gồm trong các lần tạm dừng GC, vì vậy sẽ rất hữu ích khi xác định xem các lần tạm dừng dài là do GC chậm hay do luồng tạm dừng chậm. Dưới đây là ví dụ về thời gian tạm dừng thông thường trên Nexus 5:

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

Có các lĩnh vực quan tâm khác, bao gồm tổng thời gian sử dụng và thông lượng GC. Ví dụ:

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

Dưới đây là ví dụ về cách kết xuất thời gian GC của một ứng dụng đang chạy:

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

Tại thời điểm này, thời gian của GC nằm trong anr_2020-07-13-19-23-39-817 . Đây là ví dụ đầu ra từ Google Maps:

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

Công cụ phân tích các vấn đề về tính đúng đắn của GC

Nhiều thứ có thể gây ra sự cố bên trong ART. Sự cố xảy ra khi đọc hoặc ghi vào trường đối tượng có thể cho thấy lỗi đống. Nếu GC gặp sự cố khi nó đang chạy, nó cũng có thể dẫn đến lỗi nặng. Nguyên nhân phổ biến nhất gây ra lỗi heap là mã ứng dụng không chính xác. May mắn thay, có các công cụ để gỡ lỗi GC và các sự cố liên quan đến vùng nhớ khối xếp, bao gồm các tùy chọn xác minh vùng nhớ khối xếp được chỉ định ở trên và CheckJNI.

Kiểm tra JNI

CheckJNI là chế độ bổ sung các bước kiểm tra JNI để xác minh hành vi của ứng dụng; những thứ này không được bật theo mặc định vì lý do hiệu suất. Quá trình kiểm tra phát hiện một số lỗi có thể gây ra lỗi đống, chẳng hạn như sử dụng các tham chiếu cục bộ và toàn cục không hợp lệ/cũ. Để bật CheckJNI:

adb shell setprop dalvik.vm.checkjni true

Chế độ sao chép cưỡng bức của CheckJNI rất hữu ích trong việc phát hiện việc ghi vào cuối các vùng mảng. Khi được bật, tính năng cưỡng bức sẽ khiến các hàm JNI truy cập mảng trả về các bản sao có vùng màu đỏ. Vùng màu đỏ là vùng ở cuối/bắt đầu của con trỏ trả về có giá trị đặc biệt, giá trị này được xác minh khi mảng được giải phóng. Nếu các giá trị trong vùng màu đỏ không khớp với những gì được mong đợi thì đã xảy ra lỗi tràn bộ đệm hoặc chạy thiếu. Điều này khiến CheckJNI bị hủy bỏ. Để bật chế độ ép buộc:

adb shell setprop dalvik.vm.jniopts forcecopy

Một ví dụ về lỗi mà CheckJNI sẽ phát hiện là lỗi ghi vào cuối mảng thu được từ GetPrimitiveArrayCritical . Hoạt động này có thể làm hỏng vùng heap Java. Nếu nội dung ghi nằm trong vùng vùng màu đỏ của CheckJNI thì CheckJNI sẽ phát hiện được sự cố khi gọi ReleasePrimitiveArrayCritical tương ứng. Nếu không, việc ghi sẽ làm hỏng một số đối tượng ngẫu nhiên trong vùng heap Java và có thể gây ra sự cố GC trong tương lai. Nếu bộ nhớ bị hỏng là trường tham chiếu thì GC có thể bắt lỗi và in ra lỗi Đã thử đánh dấu <ptr> không chứa bất kỳ khoảng trắng nào .

Lỗi này xảy ra khi GC cố gắng đánh dấu một đối tượng mà nó không thể tìm thấy khoảng trống. Sau khi kiểm tra này không thành công, GC duyệt qua các gốc và cố gắng xem liệu đối tượng không hợp lệ có phải là gốc hay không. Từ đây, có hai lựa chọn: Đối tượng là đối tượng gốc hoặc đối tượng không phải gốc.

Ví dụ gốc không hợp lệ

Trong trường hợp đối tượng là gốc không hợp lệ, nó sẽ in một số thông tin hữu ích: 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

Trong trường hợp này, vreg=1 bên trong com.google.gwt.collections.JavaReadableJsArray.get được cho là chứa tham chiếu heap nhưng chứa con trỏ địa chỉ không hợp lệ 0x2 . Đây là một gốc không hợp lệ. Để gỡ lỗi sự cố này, hãy sử dụng oatdump trên tệp oat và xem phương pháp có gốc không hợp lệ. Trong trường hợp này, lỗi hóa ra là lỗi trình biên dịch trong phần phụ trợ x86. Đây là danh sách thay đổi đã sửa nó: https://android-review.googlesource.com/#/c/133932/

Ví dụ về đối tượng bị hỏng

Nếu đối tượng không phải là root, hãy xuất ra kết quả tương tự như các bản in sau:

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

Khi lỗi đống không phải là gốc không hợp lệ thì rất khó để gỡ lỗi. Thông báo lỗi này cho biết có ít nhất một đối tượng trong vùng heap trỏ đến đối tượng không hợp lệ.