العمليات في Linux: ps وtop وhtop وkill والإشارات وnice
تُعرض عمليات Linux بالأمر ps aux (لقطة واحدة)، وبالأمرين top وhtop (قائمة متجددة مع الحمل). وتُنهى العملية بالأمر kill PID الذي يرسل افتراضياً إشارة SIGTERM المهذبة، ولا يُلجأ إلى kill -9 (SIGKILL) إلا إذا لم تستجب العملية. وتُضبط الأولوية بـ nice عند التشغيل وبـ renice لعملية تعمل، ضمن المدى من -20 إلى 19.
كل برنامج يعمل في Linux عملية لها رقم PID خاص بها ومالك وحالة وأولوية. يمكن عرض العمليات بالأوامر ps وtop وhtop، وإنهاؤها بالأمر kill، وتغيير أولويتها بـnice وrenice. وفيما يلي نشرح كيفية قراءة مخرجات هذه الأوامر، وأي إشارة ترسل ومتى، ولماذا لا ينبغي أن يكون kill -9 أول ما يخطر ببالك.
ما هي العملية وما هو PID
العملية هي برنامج أثناء تنفيذه: الشيفرة والذاكرة والملفات المفتوحة ومجموعة من الخصائص. يمنح النواة لكل عملية معرّفاً فريداً هو PID، ويحفظ كذلك PPID وهو رقم الأب الذي أطلقها. وأول عملية في النظام برقم PID 1 هي عادةً systemd، وهي «الجد» لكل العمليات الأخرى.
تظهر العملية الجديدة في خطوتين. أولاً يستدعي الأب fork() فيحصل على نسخة منه، ثم تستدعي النسخة execve() فتستبدل شيفرتها بشيفرة البرنامج الجديد. وعندما تكتب ls في الطرفية، ينفذ bash هذا بالضبط، وينتظر انتهاء الابن عبر wait().
$ echo $$ # PID الصدفة الحالية
4182
$ ps -o pid,ppid,cmd -p $$
PID PPID CMD
4182 4170 -bash
عرض العمليات بالأمر ps
يلتقط ps لقطة واحدة: يعرض العمليات في لحظة التشغيل ثم ينتهي. ومن دون معاملات يعرض عمليات الطرفية الحالية فقط، لذلك يُستخدم عملياً أحد الخيارين التاليين في الغالب.
$ ps aux | head -5
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.3 168540 12780 ? Ss 09:12 0:03 /sbin/init
root 2 0.0 0.0 0 0 ? S 09:12 0:00 [kthreadd]
www-data 1532 1.2 2.1 412308 86420 ? S 09:15 1:47 php-fpm: pool www
postgres 1610 0.4 3.8 221004 154312 ? Ss 09:15 0:31 postgres: checkpointer
هنا a تعني عمليات كل المستخدمين، وu تعني التنسيق المفصّل مع المالك، وx تعني تضمين العمليات التي لا طرفية لها (الخدمات الخلفية). وصيغة System V البديلة هي ps -ef، وتعرض PPID، وهذا مفيد لمعرفة من أطلق من.
| العمود | المعنى |
|---|---|
PID | معرّف العملية |
%CPU، %MEM | حصة المعالج والذاكرة الفعلية |
VSZ | الذاكرة الافتراضية بالكيلوبايت (بما فيها غير المحمّل في RAM) |
RSS | الذاكرة الفعلية المشغولة بالكيلوبايت |
STAT | حالة العملية (R وS وD وZ وT) والأعلام |
TIME | وقت المعالج المتراكم، لا مدة التشغيل |
حيل مفيدة مع ps
# أعلى 10 عمليات من حيث الذاكرة
ps aux --sort=-%mem | head -11
# أعلى 10 عمليات من حيث المعالج
ps aux --sort=-%cpu | head -11
# أعمدة مخصصة
ps -eo pid,ppid,user,ni,stat,etime,cmd
# شجرة العمليات
ps -ef --forest
pstree -p
# البحث عن PID بالاسم
pgrep -a nginx
pidof nginx
خطأ كلاسيكي هو البحث بـps aux | grep nginx فيظهر في النتيجة الأمر grep نفسه. استخدم pgrep أو الحيلة grep [n]ginx، التي لا تطابق سطر الأمر الخاص بها.
حالات العمليات: R وS وD وZ وT
الحرف في العمود STAT ليس زائداً، بل هو الحالة الفعلية للعملية. ومنها يُفهم الحمل، وهل سينفع kill أصلاً.
| الرمز | الحالة | المعنى العملي |
|---|---|---|
R | Running | تعمل أو تنتظر دورها في المعالج |
S | Interruptible sleep | تنتظر حدثاً (شبكة، إدخال، مؤقت)؛ الحالة الطبيعية لمعظم العمليات |
D | Uninterruptible sleep | تنتظر إدخال/إخراج داخل النواة، ولا تُسلَّم لها الإشارات |
Z | Zombie | انتهت، لكن أباها لم يأخذ رمز خروجها |
T | Stopped | أوقفتها إشارة SIGSTOP أو Ctrl+Z |
الرموز الإضافية بعد الحرف مفيدة أيضاً: s قائد الجلسة، و+ عملية المقدمة في الطرفية، و< أولوية أعلى، وN أولوية أدنى، وl متعددة الخيوط.
عملية في الحالة D
العملية في D موجودة داخل استدعاء نظامي وتنتظر مثلاً ردّ القرص أو شبكة NFS معلّقة. لا تصلها أي إشارة، حتى SIGKILL. لذلك يكون kill -9 عديم الفائدة هنا: ابحث عن سبب الانتظار بالنظر في iostat وdmesg وحالة التخزين الشبكي.
العمليات الزومبي
الزومبي ميتة بالفعل: لا تستهلك معالجاً ولا ذاكرة، بل تشغل سطراً فقط في جدول العمليات. ولا يمكن قتلها لأنها منتهية أصلاً. وتختفي عندما يستدعي أبوها wait()، أو عندما ينتهي الأب نفسه فيتبناها PID 1.
# البحث عن الزومبي وآبائها
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/'
الزومبي الواحد لا ضرر منه. أما إذا كانت بالمئات وتزداد، فالخطأ في البرنامج الأب، ويجب إصلاحه أو إعادة تشغيله.
top: العمليات والحمل في الوقت الفعلي
يعرض top القائمة نفسها، لكنه يحدّثها كل بضع ثوانٍ ويعرض ملخصاً للنظام. وهو أول أمر يُشغَّل عندما «يتباطأ الخادم».
top - 14:21:07 up 12 days, 3:02, 2 users, load average: 1.84, 1.20, 0.95
Tasks: 213 total, 2 running, 211 sleeping, 0 stopped, 0 zombie
%Cpu(s): 23.1 us, 4.2 sy, 0.0 ni, 70.3 id, 1.9 wa, 0.0 hi, 0.5 si, 0.0 st
MiB Mem : 7821.4 total, 412.6 free, 3105.8 used, 4303.0 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 4398.2 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1532 www-data 20 0 412308 86420 14212 R 38.2 1.1 1:47.31 php-fpm
1610 postgres 20 0 221004 154312 148900 S 6.0 1.9 0:31.08 postgres
أهم ما في السطر %Cpu(s): us كود المستخدم، وsy النواة، وid الخمول، وwa انتظار القرص. وارتفاع wa مع معالج فارغ علامة واضحة على أن عنق الزجاجة في الإدخال والإخراج.
مفاتيح top السريعة
| المفتاح | الإجراء |
|---|---|
P / M | ترتيب حسب المعالج / حسب الذاكرة |
1 | عرض كل نواة على حدة |
c | سطر الأمر الكامل |
u | تصفية حسب المستخدم |
k | إرسال إشارة إلى عملية |
r | تغيير nice للعملية |
H | عرض الخيوط |
q | خروج |
للسكريبتات والسجلات يفيد الوضع الدفعي: يعرض top -b -n 1 | head -20 لقطة واحدة دون تفاعل. ولمتابعة عملية بعينها استخدم top -p 1532.
Load Average هو طابور وليس نسبة مئوية
الأرقام الثلاثة في load average هي متوسط طول الطابور خلال 1 و5 و15 دقيقة. وتدخل في Linux إلى هذا الطابور العمليات في الحالتين R وD، أما النوم العادي S فلا. ويُقارن الحمل بعدد الأنوية (nproc): على 4 أنوية تعني القيمة 4 تحميلاً كاملاً، والقيمة 12 تعني طابوراً ثلاثة أضعاف الإمكانات.
إذا كان الحمل مرتفعاً والمعالج خامل، فابحث عن العمليات في D: ps -eo stat,pid,cmd | grep '^D'. وغالباً ما يكون السبب قرصاً بطيئاً أو تخزيناً شبكياً.
htop: بديل مريح لـ top
يعرض htop المعلومات نفسها، لكن بمؤشرات ملونة لكل نواة، مع التمرير ودعم الفأرة وشجرة العمليات. وعادةً يلزم تثبيته: sudo apt install htop أو sudo dnf install htop.
F3أو/— البحث عن عملية بالاسم؛F4— مرشّح يُبقي المطابقات فقط؛F5أوt— شجرة «الأب — الأبناء»؛F6— اختيار عمود الترتيب؛F7/F8— خفض nice أو رفعه؛F9— قائمة الإشارات للعملية المختارة؛Space— تحديد عدة عمليات لإجراء جماعي.
على الخوادم التي لا يمكن فيها تثبيت شيء، يكفي top، فكل العمليات الأساسية موجودة فيه أيضاً.
إنهاء العملية: kill والإشارات
لا يقوم الأمر kill بـ«القتل» في الحقيقة، بل يرسل إشارة إلى العملية. وما يحدث بعد ذلك يعتمد على الإشارة وعلى طريقة معالجة البرنامج لها.
| الإشارة | الرقم | الغرض |
|---|---|---|
SIGHUP | 1 | انقطاع الطرفية؛ كثير من الخدمات تعيد قراءة الإعداد عندها |
SIGINT | 2 | المقاطعة، أي ما يفعله Ctrl+C |
SIGKILL | 9 | إنهاء قسري من النواة، ولا يمكن اعتراضه |
SIGTERM | 15 | طلب بالإنهاء بهدوء؛ وهي الافتراضية في kill |
SIGSTOP | 19 | إيقاف مؤقت، ولا يمكن اعتراضه |
SIGCONT | 18 | متابعة عملية متوقفة |
SIGTSTP | 20 | إيقاف من الطرفية، أي Ctrl+Z |
الأرقام موضحة لمعماريتي x86 وARM؛ والقائمة الكاملة تعرضها kill -l. وكتابة اسم الإشارة أدق من كتابة رقمها.
kill 1532 # SIGTERM
kill -TERM 1532 # الشيء نفسه صراحةً
kill -HUP $(pidof nginx) # إعادة قراءة الإعداد
kill -STOP 1532; kill -CONT 1532
kill -0 1532 && echo "العملية حية"
الإشارة 0 لا ترسل شيئاً، بل تتحقق فقط من وجود العملية ومن صلاحيتك لمراسلتها، وهذا مفيد في السكريبتات.
لماذا لا تبدأ بـ kill -9
تعطي SIGTERM البرنامجَ فرصة لإغلاق الملفات وتفريغ المخازن وحذف ملفات القفل وإنهاء المعاملات بشكل صحيح. أما SIGKILL فيقطع كل شيء فوراً: تضيع البيانات غير المكتملة وتبقى الملفات المؤقتة، وقد تدخل قاعدة البيانات عند التشغيل التالي في مرحلة الاستعادة.
التسلسل الصحيح هو:
- أرسل
kill PID(SIGTERM). - انتظر من 5 إلى 30 ثانية مع التحقق بـ
kill -0 PID. - فقط إذا بقيت العملية حية ولم تكن في الحالة
D— أرسلkill -9 PID.
وللخدمات التي تعمل تحت systemd لا تتعامل مع PID يدوياً: إذ يرسل systemctl stop الإشارة SIGTERM، ثم ينتظر المهلة، ثم يُكمل بـSIGKILL.
pkill وkillall: بالاسم
pkill -f "python worker.py" # بسطر الأمر الكامل
pkill -u alice # كل عمليات المستخدم
killall -TERM node # كل العمليات باسم node
pgrep -l -f worker # تحقّق أولاً مما سيقع تحت النمط
قبل أي pkill جماعي شغّل pgrep بالنمط نفسه: إذ يطابق الخيار -f أي جزء من سطر الأمر، ويسهل أن يصيب ما ليس مقصوداً.
يمكن إرسال الإشارات إلى عملياتك فقط، أما عمليات غيرك فتحتاج إلى sudo. ورسالة Operation not permitted تعني ذلك تحديداً.
أولوية العمليات: nice وrenice
قيمة nice تُخبر المجدول بمن يتنازل عن المعالج. والمدى من -20 (أعلى أولوية) إلى 19 (يتنازل للجميع)، والافتراضي 0. تظهر القيمة في top في العمود NI، أما PR فهو أولوية داخلية مشتقة.
# تشغيل مهمة ثقيلة بأولوية منخفضة
nice -n 10 tar czf backup.tar.gz /var/www
# خفض أولوية عملية قائمة
renice -n 15 -p 1532
# رفع الأولوية (لـroot فقط)
sudo renice -n -5 -p 1610
# كل عمليات المستخدم
sudo renice -n 10 -u alice
يستطيع المستخدم العادي خفض أولوية عملياته فقط، والقيم السالبة متاحة لـroot وحده. وتجدر الإشارة إلى حدّ nice: إنه يؤثر في المعالج فقط. إذا كانت المهمة تبطئ النظام عبر القرص، فاستخدم ionice -c3 الأمر، وهي فئة الخمول التي تحصل على القرص فقط حين لا يحتاجه أحد.
العمليات الخلفية ومهام الصدفة
يمكن تشغيل أمر في الخلفية بإضافة &، أو إيقافه مؤقتاً بـCtrl+Z. وتحتفظ الصدفة بقائمة من المهام تُدار بأوامر مدمجة.
$ long_task &
[1] 5120
$ jobs
[1]+ Running long_task &
$ fg %1 # إعادتها إلى المقدمة
^Z # إيقاف مؤقت (SIGTSTP)
$ bg %1 # متابعتها في الخلفية
عند إغلاق الطرفية ترسل الصدفة SIGHUP إلى المهام فتنتهي. ولكي تبقى العملية بعد الخروج شغّلها عبر nohup الأمر &، أو افصلها بالأمر disown، أو استخدم tmux. وللعمل الدائم الأفضل تحويلها إلى خدمة systemd.
سيناريوهات تشخيص شائعة
من يستهلك المعالج
top -o %CPU # أو P داخل top
ps -eo pid,user,%cpu,etime,cmd --sort=-%cpu | head
إذا كانت عملية تستهلك المعالج دون فائدة، فاخفض أولويتها أولاً بـrenice، فهذا آمن ويمنحك وقتاً لفهم الأمر.
من يشغل المنفذ
sudo ss -ltnp | grep :8080
sudo lsof -i :8080
ستظهر في المخرجات رقم PID، ومنه يمكن الوصول عبر /proc/PID/ إلى الملف التنفيذي (exe) ومجلد العمل (cwd) والمعاملات (cmdline).
عملية اختفت فجأة
السبب الشائع هو OOM Killer الذي يقتل العمليات عند نفاد الذاكرة. للتحقق: dmesg -T | grep -i oom أو journalctl -k | grep -i "killed process".
الخلاصة
لإدارة العمليات في Linux تكفي مجموعة صغيرة من الأوامر: ps aux للقطة، وtop وhtop للمراقبة، وkill مع الإشارة الصحيحة للإنهاء، وnice/renice للأولويات. اقرأ حالة العملية قبل أن تتصرف: فالزومبي والعمليات في D لا تُعالَج بالإشارات. وابدأ دائماً بـSIGTERM، واترك kill -9 للحالات القصوى. وقد جرى شرح العمليات والذاكرة وLoad Average واستدعاءات النظام بعمق في درس Linux.
الأسئلة الشائعة
ما الفرق بين ps aux وps -ef؟
هما صيغتان لأمر واحد: aux بنمط BSD مع أعمدة %CPU وMEM وSTAT، والخيار -ef بنمط System V مع عمود PPID. وعدد العمليات المعروضة في الحالتين واحد، وهو كل عمليات النظام.
كيف أعرف عدد العمليات الجارية في النظام؟
أسهل طريقة هي النظر إلى سطر Tasks في top، أو تنفيذ ps -e --no-headers | wc -l. ولعدد الخيوط استخدم ps -eLf --no-headers | wc -l.
لماذا لا تنتهي العملية حتى بعد kill -9؟
إما أنها في الحالة D وتنتظر إدخال/إخراج داخل النواة، وإما أنها زومبي منتهية أصلاً. في الحالة الأولى ابحث عن مشكلة في القرص أو التخزين الشبكي، وفي الثانية أصلح الأب أو أعد تشغيله.
ماذا يحدث إذا أنهيت العملية ذات PID 1؟
تحمي النواة init: لا تُسلَّم له الإشارات العادية، بما فيها SIGKILL من المستخدم، ما لم يكن قد عالجها. وإذا انتهى init فعلاً يتعطل النظام بـkernel panic.
كيف أحدّ من استخدام الذاكرة لعملية؟
لخدمة systemd حدّد MemoryMax= في ملف الوحدة، ولتشغيل لمرة واحدة استخدم systemd-run --scope -p MemoryMax=500M الأمر. وهذا يعمل عبر cgroups وهو أدق من ulimit -v القديم.
يُشرح هذا الموضوع بالتفصيل مع التطبيق العملي في دورة «Linux: с нуля до уверенного администрирования».
الانتقال إلى الدورة