Một vài ghi chú về CMS GC
Java
77
GC
1
White

huydx viết ngày 03/02/2018

GC là viết tắt của Garbage Collector, là một kĩ thuật dùng trong các ngôn ngữ như java hay golang, mục đích để user (developer) không phải quan tâm đến việc giải phóng bộ nhớ một cách thủ công. Để biết thêm về GC, bạn có thể xem thêm link

CMS là tên một loại GC được sử dụng trên java (Hotspot VM) link

CMS là viết tắt của Concurrent Mark-Sweep, để sử dụng CMS thì thêm option -XX:+UseConcMarkSweepGC khi khởi động java. Có một vài điểm thu ra được từ tên của loại GC này

  1. Concurrent :GC sẽ chạy song song (concurrent) với application, trên một Thread riêng (GC Thread).
  2. Mark and Sweep: Những vùng nhớ (memory region) được GC không nhận là rác, sẽ được đánh dấu (Mark), sau đó sẽ được quét (Sweep) đi, trả về pool để tái sử dụng.

Heap region

Có một vài khái niệm mơ hồ ở trên, chúng ta sẽ đi lần lượt. Đầu tiên là khái niệm về "vùng nhớ". Về cơ bản thì thuật toán GC nào của java cũng sẽ chia vùng nhớ thành 3 vùng chính:

New -> Old -> Permenant, hay nôm na là trẻ, già, và vĩnh viễn.

Vùng New và Old sẽ nằm trên Heap của JVM (hay là vùng mà JVM có thể tự do cấp phát cho application, sẽ được qui định thông qua option -Xms-Xmx).

Vùng New sẽ được chia nhỏ ra thành 3 vùng nhỏ hơn:

  • Eden
  • Survivor 0
  • Survivor 1

Vùng Old còn được gọi một cách khác là Tenured

Về mặt ý tưởng:

  • Những object mới được cấp phát sẽ được đưa vào vùng New
  • Những object sống lâu (hay trải qua nhiều lần quét rác mà vẫn ngoan cố), sẽ được đưa vào vùng old
  • Việc quét rác ở vùng New gọi là MinorGC
  • Việc quét rác ở vùng Old gọi là Major GC

Object sống lâu?

Vậy khi nào thì các object sống lâu? Về cơ bản một object sẽ được tồn tại dựa trên Scope. Scope dễ hiểu nhất chính là function, mà bạn có thể thấy ở đoạn code dưới đây:

void foo1() {
  Integer f = 1;
  System.out.println(f);
}

int foo2() {
  Integer f = 1;
  return f;
}

Trong 2 hàm trên, thì object f ở trong foo2 sẽ sống dai hơn, khi mà nó được "chạy trốn" (escape) ra ngoài thông qua việc return. Còn object f trong foo1 thì không may mắn thế nó sẽ bị thịt sớm nhất có thể, vì nó không chạy trốn được. f càng được sử dụng ở nhiều nơi (reference), mà được sử dụng cáng nhiều bởi các object cha chú lớn tuổi khác, thì khả năng nó được sống càng cao.
Để biết một object được chạy trốn ở thời điểm nào, ra sao, chúng ta có thể tìm hiểu một kĩ thuật gọi là "Escape Analysis" (golang cũng có kĩ thuật này).

Cụ thể về MinorGC và MajorGC

MinorGC: Parallel Copy GC trên New region:

  • Thực hiện STW (Stop-The-World): copy các object sống dai từ Eden qua Survivor 0, và từ Survivor 0 qua Survivor 1. Stop The World có nghĩa là app của bạn sẽ ngừng chạy (giống như tim ngừng đập vậy). Vậy nên nếu app của bạn là một WebServer thì mọi request vào sẽ phải chờ (tương tự như bạn gọi Thread.sleep() vậy).
  • Sau Minor GC, thì các object sống dai sẽ được copy qua Survivor 0, và nếu hắn ngoan cố sẽ được copy tiếp qua Survivor 1. Còn nếu hắn không may thì sẽ bị thủ tiêu ở Eden.
  • Mỗi lần một object được copy, chúng ta gọi là "Promotion" (hay là thăng chức).
  • Điều kiện thăng chức: khi mà sau N lần quét rác mà một object vẫn ngon cố không bị thủ tiêu. Số N này được set qua option -XX:+MaxTenuringThreshold. Nếu bạn set -XX:+AlwaysTenure thì object sẽ được lên thẳng Tenure mà không qua Survivor.
  • Đặc điểm của Minor GC là mặc dù có STW nhưng sẽ nhanh, và sẽ không làm memory bị fragment (do vùng nhơ được tạo trên eden thường là vùng nhớ liên tiếp).

MajorGC: CMS GC trên Old Region:

  • Chia làm 7 phases (bạn không cần nhớ cụ thể, nhưng cần biết để có thể đọc GC log): Initial Mark -> Concurrent Mark -> Concurrent Preclean -> Concurrent Abortable Preclean -> Remark (Final Mark) -> Concurrent Sweep -> Concurrent Reset.
  • Step 1 (Initial Mark) và Step 5 (Remark) sẽ thực hiện STW (Stop-The-World)
  • Điều kiện phát sinh của MajorGC:
    • Khi object không promotion được từ Survivor lên Tenure nữa, do không còn đủ chỗ trống, hay thậm chí đủ chỗ trống nhưng do memory fragment).
    • Khi sweep quá chậm, không đủ nhanh để trả bộ nhớ về pool. (Concurrent mode failure)
    • Khi vùng nhớ Old quá một phạm vi cho phép. Thông thường vùng Old sẽ được cấp sẵn N Gb, nhưng khi nó vượt quá N Gb * X % , thì sẽ xảy ra MajorGC. X sẽ được quyết định qua -XX:CMSInitiatingOccupancyFraction

Cách đọc GC log

GC log là một thông tin rất quan trọng để bạn biết cụ thể chuyện gì đã xẩy ra bên trong JVM.
Để enable GC log thì bạn cần vài option:

  • -Xloggc:gc.log (tên file)
  • -XX:+PrintGCDetails
  • -XX:+PrintGCDateStamps
  • -XX:+HeapDumpOnOutOfMemoryError

Về cách đọc thì log được in ra khá dễ hiểu, với ví dụ như đoạn log dưới đây, bạn sẽ nhìn được một số thông tin của MinorGC

  • Lượng memory trước GC (230016k)
  • Lượng memory sau GC (4553k)
  • Tổng thời gian xử lý (STW) (0.01s)

Tương tự với đoạn log dưới đây, bạn sẽ nhìn được thông tin từ phase Initial Mark của Major GC:

  • Lượng memory của vùng Old (292...k)
  • Thời gian xử lý (STW) (0.01s)

Một số pattern

  • Bạn có rất nhiều object được tạo ra, và bạn biết chắc nó tồn tại trong thời gian thấp, nhưng GC không đủ nhanh để quét rác, dẫn đến nó lọt sang vùng old để dẫn đến MajorGC, hay thậm chí là fullGC. Bạn có thể giải quyết bằng cách tăng MaxTenuringThresHold lên.
  • GC chạy vào thời điểm quá chậm, khi vùng Old quá đầy, dẫn đến thời gian STW bị lớn. Bạn có thể giải quyết bằng cách giảm CMSInitiatingOccupancyFraction xuống, hay ... tăng spec server bằng cách tăng core (tăng số thread để chạy concurrent GC lên).

Ref

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

huydx

116 bài viết.
943 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
148 14
Introduction (Link) là một cuộc thi ở Nhật, và cũng chỉ có riêng ở Nhật. Đây là một cuộc thi khá đặc trưng bởi sự thú vị của cách thi của nó, những...
huydx viết gần 2 năm trước
148 14
White
118 15
Happy programmer là gì nhỉ, chắc ai đọc xong title của bài post này cũng không hiểu ý mình định nói đến là gì :D. Đầu tiên với cá nhân mình thì hap...
huydx viết hơn 3 năm trước
118 15
White
95 10
(Ảnh) Mở đầu Chắc nhiều bạn đã nghe đến khái niệm oauth. Về cơ bản thì oauth là một phương thức chứng thực, mà nhờ đó một web service hay một ap...
huydx viết 3 năm trước
95 10
Bài viết liên quan
White
0 0
Trong bài viết này, một số hình ảnh hoặc nọi dung có thể bị thiếu do quá trình chế bản. Vui lòng xem nội dung ở blog gốc sau: (Link) (Link), chúng...
programmerit viết gần 3 năm trước
0 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
116 bài viết.
943 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!