Một service trên production đang treo, hoặc ngốn RAM bất thường, và bạn muốn biết chính xác nó đang làm gì — nhưng không dám dừng nó, cũng không muốn strace làm nó chậm thêm. May thay, Linux có một "cửa sổ" đọc-được cho mọi tiến trình đang chạy: thư mục /proc/<pid>. Đây không phải file thật trên đĩa mà là hệ thống file ảo do kernel sinh ra ngay khi bạn đọc — phơi bày trạng thái sống của tiến trình mà không hề can thiệp vào nó. Bài này (phần 3 loạt Debug) chạy thật để thấy /proc/<pid> trả lời những câu hỏi debug thường gặp nhất.

/proc là hệ thống file ảo của kernel

Mỗi tiến trình có một thư mục /proc/<pid> (ví dụ /proc/1234). Nội dung không nằm trên đĩa — kernel tạo ra tại thời điểm bạn đọc, phản ánh trạng thái ngay lúc đó. Vì chỉ đọc, nó không làm tiến trình chậm và xem được cả tiến trình đang treo.

pid=$(pgrep myapp)   # tìm PID của tiến trình
cat /proc/$pid/cmdline    # lệnh khởi động

Ảnh chụp đoạn mã nền tối minh hoạ proc pid cửa sổ nhìn vào tiến trình đang sống không cần dừng nó, proc là hệ thống file ảo do kernel sinh ra mỗi tiến trình có một thư mục proc pid không phải file thật trên đĩa mà kernel dựng khi bạn đọc xem trạng thái sống của tiến trình mà không cần strace hay dừng nó pid bằng pgrep myapp tìm PID, các file quan trọng proc pid cmdline lệnh khởi động đầy đủ kèm tham số proc pid status trạng thái bộ nhớ VmRSS VmSize số thread proc pid fd các file descriptor đang mở file socket pipe proc pid cwd thư mục làm việc symlink proc pid exe đường dẫn binary thật đang chạy proc pid maps bản đồ bộ nhớ code heap stack so proc pid environ biến môi trường, giải đáp câu hỏi thực tế ngay app đang mở file socket nào ls -l proc pid fd app chạy từ binary thư mục nào readlink exe cwd app dùng bao nhiêu RAM thật grep VmRSS status app khởi động với tham số gì cat cmdline, ưu điểm so với strace proc chỉ đọc trạng thái không làm chậm tiến trình xem được ngay cả tiến trình đang treo không phản hồi

Hình 1: /proc/<pid> là hệ thống file ảo kernel sinh ra; các file quan trọng (cmdline, status, fd/, cwd, exe, maps, environ) trả lời câu hỏi debug; ưu điểm so với strace: chỉ đọc, không làm chậm, xem được cả tiến trình treo.

Đo thật: soi một tiến trình python đang giữ file

Mình chạy một tiến trình python mở một file rồi ngủ, và soi nó qua /proc:

Ảnh chụp bảng kết quả chạy thật proc pid python giữ 1 file output thật, một cmdline cộng status trích cmdline ra python3 hold.py status ra State S sleeping Threads 1 VmSize 18316 kB VmRSS 12316 kB RAM thật, ba fd file descriptor đang mở 0 ra dev null 1 ra pipe 2 ra pipe 3 ra work u_proc data.log đúng file app đã mở, bốn cwd cộng exe symlink cwd ra work u_proc thư mục làm việc exe ra usr bin python3.11 binary thật đang chạy, năm maps bản đồ bộ nhớ 00400000-00915000 r-xp usr bin python3.11 code thực thi 00930000-00a60000 rw-p usr bin python3.11 data đọc ghi thấy code heap stack thư viện được ánh xạ vào đâu

Hình 2: Chạy thật — cmdline = python3 hold.py; status cho State: S (sleeping), VmRSS: 12316 kB (RAM thật); fd/ cho fd 3 → /work/u_proc/data.log (file đã mở); cwd/exe → thư mục và binary thật; maps cho code (r-xp) và data (rw-p) của python.

  • cmdline: lệnh khởi động đầy đủ kèm mọi tham số — python3 hold.py. Hữu ích khi ps cắt ngắn hoặc bạn cần biết chính xác cờ nào được truyền.
  • status: bảng trạng thái — State: S (sleeping) (tiến trình đang ngủ chờ), Threads: 1, và bộ nhớ. VmRSS: 12316 kB là RAM vật lý thật đang dùng (bài sau đào sâu RSS vs VSZ). Đây là cách nhanh nhất kiểm một tiến trình có rò rỉ bộ nhớ không: theo dõi VmRSS tăng dần.
  • fd/: liệt kê mọi file descriptor đang mở dưới dạng symlink — 0 → /dev/null, 1,2 → pipe, và 3 → /work/u_proc/data.log (đúng file app đã mở). Đây là công cụ vàng để trả lời "app đang giữ file/socket nào?" và phát hiện rò rỉ fd (bài sau).
  • cwd/exe: readlink /proc/$pid/cwd cho thư mục làm việc (/work/u_proc), exe cho binary thật đang chạy (/usr/bin/python3.11) — hữu ích khi nghi ngờ tiến trình chạy nhầm phiên bản hoặc từ thư mục lạ.
  • maps: bản đồ không gian địa chỉ — code (r-xp, chỉ đọc + thực thi), data (rw-p), heap, stack, và các thư viện .so được ánh xạ vào đâu. Dùng khi debug lỗi bộ nhớ hoặc muốn biết thư viện nào được nạp.

Đánh đổi cần cân nhắc

/proc là ảnh chụp tức thời, không phải theo dõi liên tục. Mỗi lần cat cho trạng thái lúc đó. Để thấy xu hướng (RAM tăng dần, fd tăng dần = rò rỉ), phải đọc lặp lại theo thời gian (watch -n1 grep VmRSS /proc/$pid/status). /proc giỏi trả lời "bây giờ thế nào", còn "thay đổi ra sao" thì cần lấy mẫu nhiều lần hoặc công cụ giám sát.

Quyền truy cập giới hạn theo chủ sở hữu. Bạn đọc được đầy đủ /proc/<pid> của tiến trình mình sở hữu; với tiến trình của user khác, nhiều file (như environ, maps) bị chặn trừ khi là root. environ đặc biệt nhạy cảm vì có thể chứa bí mật (mật khẩu trong biến môi trường) — đây cũng là lý do đừng để bí mật trong biến môi trường của tiến trình dùng chung máy.

PID bị tái sử dụng — cẩn thận trong script. Sau khi một tiến trình chết, PID của nó có thể được cấp lại cho tiến trình khác. Một script đọc /proc/$pid dựa trên PID cũ có thể vô tình đọc nhầm tiến trình mới. Với giám sát lâu dài, kiểm lại cmdline/exe để chắc đúng tiến trình, hoặc dùng công cụ theo dõi theo cgroup/định danh ổn định hơn.

Ba ý mang về

  1. /proc/<pid> là cửa sổ đọc-được vào tiến trình sống: hệ thống file ảo kernel sinh ra, xem trạng thái mà không làm chậm hay dừng tiến trình — dùng được cả khi nó đang treo, khác với strace.
  2. Trả lời câu hỏi debug thường gặp ngay: đo thật fd/ cho thấy file đang mở (data.log), status cho RAM thật (VmRSS 12316 kB), exe/cwd cho binary và thư mục, cmdline cho tham số đầy đủ.
  3. Là ảnh chụp, không phải theo dõi: đọc lặp lại để thấy xu hướng (rò rỉ RAM/fd); quyền giới hạn theo chủ sở hữu (environ nhạy cảm), và cẩn thận PID tái sử dụng khi viết script giám sát.

Nguồn

Phần sau ta đào sâu vào một mục của /proc: file descriptor — đếm fd đang mở, phát hiện rò rỉ fd khiến app "too many open files", và giới hạn ulimit.