Giới thiệu về jcmd
jcmd là công cụ dòng lệnh được giới thiệu từ JDK 7, đóng vai trò như một giải pháp thống nhất để thay thế các tiện ích truyền thống như jstack, jmap, và jinfo. Dựa trên cơ chế Attach API của JVM, jcmd cho phép tương tác trực tiếp với tiến trình Java đang chạy nhằm thu thập thông tin trạng thái, thực thi hành động điều khiển hoặc truy xuất cấu hình — biến nó thành lựa chọn hàng đầu khi cần chẩn đoán sự cố trong môi trường sản phẩm.
Cú pháp cơ bản
jcmd <pid | tên_class_chính> <lệnh> [tùy_chọn]
- pid: ID tiến trình Java (ưu tiên sử dụng).
- tên_class_chính: Tên lớp chứa phương thức
main(), chỉ dùng khi không xác định được PID. - lệnh: Hành động chẩn đoán mong muốn, ví dụ:
Thread.print,GC.run. - tùy_chọn: Tham số bổ sung tùy theo lệnh.
Để xem danh sách đầy đủ các lệnh hỗ trợ:
jcmd <pid> help
Nhóm lệnh theo chức năng chính
1. Phân tích luồng và ngăn xếp
Thread.print – Ghi lại hình ảnh ngăn xếp tất cả luồng (thế chỗ jstack):
jcmd 12345 Thread.print -l > stacktrace.log
- Tùy chọn
-lhiển thị chi tiết khóa (lock), bao gồm cả các đồng bộ hóa từjava.util.concurrent. - An toàn để dùng trong hệ thống đang vận hành vì không gây Full GC.
Từ JDK 17 trở đi, có thêm lệnh:
jcmd 12345 Thread.dump_to_file /var/log/app/thread-dump.txt
Ghi trực tiếp vào file, tránh rủi ro do shell xử lý sai luồng đầu ra.
2. Quản lý bộ nhớ và thu gom rác
GC.run – Kích hoạt thu gom rác toàn phần:
jcmd 12345 GC.run
Lưu ý quan trọng: Gây dừng ứng dụng tạm thời (STW). Chỉ nên dùng để kiểm thử hoặc giải phóng bộ nhớ khẩn cấp.
GC.run_finalization – Thực thi hàng đợi finalize:
jcmd 12345 GC.run_finalization
Kích hoạt phương thức finalize() của các đối tượng chờ hủy. Không khuyến khích phụ thuộc vào tính năng này.
VM.gc_class_histogram – Hiển thị biểu đồ số lượng đối tượng đang sống:
jcmd 12345 VM.gc_class_histogram
Tương đương jmap -histo:live, nhưng sẽ kích hoạt Full GC. Nên cân nhắc kỹ trước khi dùng.
Nếu muốn thống kê lớp mà không gây Full GC, có thể dùng:
jcmd 12345 GC.class_stats
Yêu cầu khởi động JVM kèm cờ -XX:+UnlockDiagnosticVMOptions.
3. Kiểm tra cấu hình và thông tin hệ thống
VM.flags – Xem các tham số khởi động JVM:
jcmd 12345 VM.flags
jcmd 12345 VM.flags -all # Bao gồm cả giá trị mặc định
Dễ dàng tìm kiếm cài đặt cụ thể như heap size:
jcmd 12345 VM.flags | grep MaxHeap
VM.system_properties – Liệt kê tất cả thuộc tính hệ thống (-Dkey=value):
jcmd 12345 VM.system_properties
Bao gồm user.dir, file.encoding, spring.profiles.active…
VM.command_line (JDK 9+) – Hiển thị câu lệnh đầy đủ dùng để khởi động ứng dụng:
jcmd 12345 VM.command_line
VM.version – In phiên bản chi tiết của JVM:
jcmd 12345 VM.version
4. Phân tích bộ nhớ native (cần bật NMT)
Phải khởi động JVM với:
-XX:NativeMemoryTracking=summary
hoặc
-XX:NativeMemoryTracking=detail
Sau đó dùng lệnh:
jcmd 12345 VM.native_memory summary
Xem tổng hợp bộ nhớ theo nhóm: Class, Thread, Code Cache, GC, Internal…
Một số tùy chọn nâng cao:
| Tùy chọn | Mô tả |
|---|---|
summary |
Tổng quan theo loại bộ nhớ |
detail |
Chi tiết từng khối bộ nhớ (khá dài) |
baseline |
Thiết lập mốc so sánh ban đầu |
summary.diff |
Hiển thị sự thay đổi kể từ mốc baseline |
Ví dụ theo dõi rò rỉ bộ nhớ native:
jcmd 12345 VM.native_memory baseline
sleep 60
jcmd 12345 VM.native_memory summary.diff
Phần Internal thường liên quan đến DirectByteBuffer, Netty, JNI.
5. Giám sát hiệu năng
PerfCounter.print – In các bộ đếm nội bộ của JVM:
jcmd 12345 PerfCounter.print
Hiển thị số lần GC, thời gian biên dịch Just-In-Time, số lượng luồng…
ManagementAgent.start – Bật JMX runtime:
jcmd 12345 ManagementAgent.start \
jmxremote.port=8888 \
jmxremote.authenticate=false \
jmxremote.ssl=false
Hữu ích khi cần kết nối VisualVM hoặc JConsole mà chưa bật JMX từ đầu. Không nên tắt xác thực trong môi trường production.
6. Chẩn đoán chuyên sâu
VM.start_flight_recording – Kích hoạt ghi dữ liệu hiệu năng bằng Java Flight Recorder (JFR):
jcmd 12345 VM.start_flight_recording \
name=DiagSession \
settings=profile \
duration=120s \
filename=/tmp/diag.jfr
JFR có độ trễ thấp (<1%), phù hợp giám sát trực tiếp trên hệ thống thật.
VM.class_hierarchy (JDK 15+) – Xem cây kế thừa của một lớp:
jcmd 12345 VM.class_hierarchy java.util.ArrayList
Kỹ thuật sử dụng nâng cao
Áp dụng hàng loạt lên nhiều tiến trình:
for pid in $(jps | grep -E 'MyApp|Backend' | awk '{print $1}'); do
jcmd $pid Thread.print > /tmp/stack-$pid.log
done
Theo dõi liên tục với watch:
watch -n 3 'jcmd 12345 PerfCounter.print | grep "sun.gc.collector.0.time"'
Sử dụng trong container:
- Đảm bảo thư mục
/tmpcó quyền ghi. - Nếu gặp lỗi "Unable to open socket file", có thể dùng
kill -3 <pid>để lấy thread dump.
Lưu ý quan trọng
- Chỉ có thể attach vào tiến trình nếu cùng user hoặc là root.
- Một số lệnh như
GC.runhayVM.gc_class_histogramgây STW. - Tính năng Native Memory Tracking phải được kích hoạt từ lúc khởi động JVM.
- JFR miễn phí trên OpenJDK từ phiên bản 11; Oracle JDK 8 yêu cầu giấy phép thương mại.
Bảng tra cứu nhanh
| Mục đích | Lệnh tương ứng |
|---|---|
| Lấy thread dump | jcmd <pid> Thread.print -l |
| Xem tham số JVM | jcmd <pid> VM.flags |
| Xem thuộc tính hệ thống | jcmd <pid> VM.system_properties |
| Kích hoạt Full GC | jcmd <pid> GC.run |
| Thống kê đối tượng sống | jcmd <pid> VM.gc_class_histogram |
| Phân tích bộ nhớ native | jcmd <pid> VM.native_memory summary |
| Bắt đầu ghi JFR | jcmd <pid> VM.start_flight_recording ... |
| Mở JMX tại runtime | jcmd <pid> ManagementAgent.start ... |
Kết luận
jcmd đã trở thành tiêu chuẩn vàng trong việc chẩn đoán ứng dụng Java hiện đại nhờ khả năng tích hợp đa chức năng, mức độ can thiệp thấp và tương thích tốt với kiến trúc đám mây, container. Việc làm chủ jcmd giúp kỹ sư DevOps và SRE phản ứng nhanh hơn với sự cố hiệu năng, bộ nhớ hay tắc nghẽn luồng.