دسترسی به دامپ ترد در جاوا — به زبان ساده
در این مقاله به بررسی روشهای مختلف دسترسی به دامپ ترد در جاوا خواهیم پرداخت. منظور از دامپ ترد (Dump Thread) یک اسنپشات از حالت همه تردهای یک پردازش جاوا است. حالت هر ترد به وسیله یک «رد پشته» (Stack Trace) ارائه مییابد که محتوای پشته را نشان میدهد. دامپ ترد برای عیبیابی مشکلات مناسب است، زیرا فعالیت ترد را نمایش میدهد. دامپهای ترد به صورت متن ساده نوشته میشوند. از این رو میتوانیم محتوای آنها را در یک فایل ذخیره کرده و در ادامه در یک ادیتور متنی بررسی کنیم.
در بخش بعدی به معرفی ابزارها و رویکردهای مختلف موجود برای تولید دامپ ترد خواهیم پرداخت.
استفاده از ابزارهای JDK برای دسترسی به دامپ ترد در جاوا
JDK چند ابزار ارائه کرده است که با استفاده از آنها میتوان به دامپ یک ترد در اپلیکیشن جاوا دسترسی یافت. همه این ابزارها زیر پوشه bin درون دایرکتوری home در JDK قرار دارند. از این رو میتوانید این ابزارها را تا زمانی که این دایرکتوری در مسیر سیستم شما موجود است، از خط فرمان اجرا کنید.
Jstack
Jstack یک ابزار خط فرمان در JDK است که با استفاده از آن میتوانیم به دامپ یک ترد دسترسی پیدا کنیم. این ابزار pid مربوط به پردازش را گرفته و دامپ ترد را در کنسول نمایش میدهد. همچنین میتوانیم خروجی را به یک فایل هدایت کنیم.
در ادامه ساختار ابتدایی این دستور را برای دسترسی به دامپ یک ترد میبینید:
jstack [-F] [-l] [-m] <pid>
همه فلگها اختیاری هستند. معنی آنها به شرح زیر است:
- F-: این گزینه دامپ ترد را الزام میکند. استفاده از این فلگ زمانی مفید است که jstack پاسخگو نباشد یعنی پردازش هنگ کرده باشد.
- l-: این گزینه به ابزار دستور میدهد که به دنبال سنکرونایزرهای قابل تملک در هیپ بگردد و آنها را قفل کند.
- m-: این گزینه فریمهای پشته نیتیو (C و ++C) را علاوه بر فریمهای پشته جاوا پرینت میکند.
این اطلاعات را با بررسی یک مثال عملی از دامپ ترد جاوا در یک فایل بررسی میکنیم:
jstack 17264 > /tmp/threaddump.txt
به خاطر داشته باشید که برای به دست آوردن pid پردازشهای جاوا میتوانید به سادگی از دستور jps استفاده کنید.
Java Mission Control
Java Mission Control یا به اختصار JMC یک ابزار GUI است که دادهها را از اپلیکیشنهای جاوا گردآوری کرده و آنالیز میکند. پس از آن که JMC اجرا میشود، فهرستی از پردازشهای جاوا را نشان میدهد که روی ماشین لوکال اجرا شدهاند. همچنین میتوانیم از طریق JMC به پردازش ریموت جاوا وصل شویم.
امکان راست-کلیک کردن روی پردازش و کلیک کردن روی گزینه Start Flight Recording نیز برای نمایش دامپهای ترد روی زبانه Threads وجود دارد:
Jvisualvm
Jvisualvm یک ابزار با رابط کاربری گرافیکی است که به ما امکان رصد، عیبیابی و پروفایل کردن اپلیکیشنهای جاوا را میدهد. این GUI ساده است و با داشتن ماهیتی کاملاً شهودی، استفاده از آن کاملاً آسان است.
یکی از گزینههای فروان آن به ما امکان میدهد که به دامپ یک ترد دسترسی پیدا کنیم. اگر روی یک پردازش جاوا راست-کلیک و گزینه Thread Dump را انتخاب کنیم، این ابزار یک دامپ ترد ایجاد کرده و آن را در زبانه جدیدی باز میکند:
از نسخه JDK 9 به بعد، Visual VM دیگر در توزیعهای Oracle JDK و Open JDK ارائه نمیشود. از این رو اگر از جاوا 9 یا بالاتر استفاده میکنید، میتوانید JVisualVM را از سایت پروژه اوپن سورس Visual VM (+) به دست آورید.
Jcmd
Jcmd ابزاری است که با ارسال درخواستهای فرمان به JVM کار میکند. با این که این ابزار قدرتمند است، اما هیچ گونه کارکرد ریموت ندارد. ما باید از آن روی همان دستگاهی استفاده کنیم که پردازش جاوا در حال اجرا است.
یکی از دستورهای فروان آن به صورت Thread.print است. از این دستور میتوان برای به دست آوردن دامپ یک ترد از طریق تعیین pid پردازش استفاده کرد:
jcmd 17264 Thread.print
Jconsole
Jconsole به ما امکان بازبینی رد پشته هر ترد را میدهد. اگر jconsole را باز کنیم و به پردازش جاوا وصل شویم، میتوانیم به زبانه Threads برویم و رد پشته هر ترد را ببینیم.
جمعبندی
چنان که در این بخش دیدیم، روشهای بسیار زیادی برای دسترسی به دامپ یک ترد در جاوا با استفاده از ابزارهای JDK وجود دارد. در این بخش مزایا و معایب هر کدام از این روشها را بررسی میکنیم.
- Jstack – آسانترین و سریعترین روش برای دسترسی به دامپ ترد است. با این حال، در صورتی که از جاوا 8 به بالا استفاده میکنید، جایگزینهای بهتری نیز وجود دارند.
- Jmc - یک ابزار بهبود یافته پروفایلینگ و عیبیابی JDK است که سربار عملکردی را که از عیوب عمده ابزارهای پروفایل کردن است به شدت کاهش میدهد.
- Jvisualvm – یک ابزار سبک و متن-باز برای پروفایل کردن است که کنسول GUI مناسبی دارد.
- Jcmd – یک ابزار قوی و مناسب برای جاوا 8 به بالا است. این ابزار منفرد اهداف مختلفی دارد که شامل دامپ کردن ترد، دامپ هیپ، نمایش مشخصههای سیستم و آرگومانهای خط فرمان است.
- Jcmd – امکان بازبینی اطلاعات رد پشته ترد را فراهم میسازد.
ابزارهای خط فرمان
در سرورهای اپلیکیشن سازمانی، به دلایل امنیتی تنها JRE نصب میشود. از این رو نمیتوانیم از ابزارهای فوق به عنوان بخشی از JDK استفاده کنیم. با این حال جایگزینهای مختلف خط فرمان وجود دارند که امکان دسترسی به دامپ ترد در جاوا را فراهم میسازند.
دستور kill -3 (لینوکس و یونیکس)
آسانترین روش برای دسترسی به دامپ ترد در جاوا در سیستم شبه یونیکس از طریق دستور kill است. از این دستور میتوان برای ارسال یک سیگنال به پردازش با استفاده از فراخوانی سیستمی call() استفاده کرد. در این حالت، سیگنال 3- ارسال میشود.
با استفاده از همان pid مثالهای قبلی، به بررسی شیوه استفاده از kill برای دسترسی به دامپ ترد در جاوا میپردازیم:
kill -3 17264
در این روش، آن پردازش جاوا که سیگنال را دریافت میکند، دامپ ترد را روی خروجی استاندارد پرینت میکند. اگر پردازش جاوا را با ترکیب زیر از فلگهای تنظیمی اجرا کنیم، در این صورت دامپ ترد نیز به فایل مفروض هدایت میشود:
-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=~/jvm.log
اکنون اگر سیگنال 3- را ارسال کنیم، علاوه بر خروجی استاندارد، دامپ مورد نظر در فایل ~/jvm.log نیز در اختیار ما قرار خواهد داشت.
Ctrl + Break (ویندوز)
در سیستمهای عامل ویندوز، امکان دسترسی به دامپ ترد با استفاده از ترکیب کلیدهای Ctrl + Break وجود دارد. برای به دست آوردن یک دامپ ترد، باید به کنسول برویم تا اپلیکیشن جاوا را باز کنیم و سپس کلیدهای ترکیبی Ctrl + Break را بزنیم.
لازم به ذکر است که در برخی کیبردها کلید Break موجود نیست. از این رو در چنین مواردی، دامپ ترد را میتوان با استفاده از ترکیب کلیدهای Ctrl ،Shift و Pause به دست آورد. هر دو این دستورها دامپ ترد را در کنسول پرینت میکنند.
دسترسی به دامپ ترد به روش برنامهنویسی شده با استفاده از ThreadMxBean
آخرین راهکاری که در این مقاله برای دسترسی به دامپ ترد در جاوا بررسی میکنیم، شامل استفاده از JMX است. در این روش ما از ThreadMxBean برای دسترسی به دامپ ترد استفاده میکنیم. کدنویسی آن به شکل زیر است:
1private static String threadDump(boolean lockedMonitors, boolean lockedSynchronizers) {
2 StringBuffer threadDump = new StringBuffer(System.lineSeparator());
3 ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
4 for(ThreadInfo threadInfo : threadMXBean.dumpAllThreads(lockedMonitors, lockedSynchronizers)) {
5 threadDump.append(threadInfo.toString());
6 }
7 return threadDump.toString();
8}
در برنامه فوق، چند سطح مختلف اجرا میشوند:
- ابتدا یک StringBuffer خالی مقداردهی میشود تا اطلاعات پشته هر ترد را نگهداری کند.
- ما میتوانیم از کلاس ManagementFactory برای دسترسی به وهلهای از ManagementFactory استفاده کنیم. ManagementFactory یک کلاس فکتوری برای دریافت bean-های مدیریتشده برای پلتفرم جاوا است. علاوه بر آن یک ThreadMxBean اینترفیس مدیریت برای سیستم ترد JCM محسوب میشود.
- تعیین مقادیر lockedMonitors و lockedSynchronizers روی مقدار true نشان میدهد که سنکرونایزرهای قابل تملک به دست آمده و همه مانیتورهای قفلشده در دامپ ترد قرار دارند.
سخن پایانی
در این مقاله به بررسی روشهای مختلف برای دسترسی به دامپ ترد در جاوا پرداختیم. در این مسیر ابتدا ابزارهای مختلف JDK را بررسی کردیم و سپس جایگزینهای خط فرمان را برشمردیم. در بخش آخر نیز رویکرد برنامهنویسی شده با استفاده از JMX را معرفی کردیم.