تشخیص نشت حافظه در جاوا
نشتی حافظه زمانی رخ میدهد که در تخصیص حافظهها و آزادسازی آنها مدیریت درستی صورت نگیرد و به این ترتیب در طول زمان میتواند اجرای برنامه را با مشکل کمبود حافظه روبرو کند. تشخیص نشت حافظه تنها توسط برنامهنویس مسلط به کد امکانپذیر است و حتی پیدا کردن علت آن در یک کد چند هزار خطی برای برنامهنویس حرفهای نیز بسیار مشکل است. در این مقاله دستوراتی برای پیدا کردن منشا نشت حافظه معرفی مینماییم.
در معرفی ابزارهای پروفایلر یکی از کاربردهایی که برای آنها معرفی گردید مدیریت حافظه مصرفی بود. در این جا نیز دستورات خط فرمانی که برای پیدا کردن مکان نشت حافظه به ما کمک میکنند را توضیح میدهیم. هرزمان که به نشت حافظه مشکوک میشویم باید این دستورات را استخراج کنیم. پس اینجا برای استفاده آیندگان آنها را جمعآوری میکنیم.
ابتدا از دستور زیر برای مانیتور کردن پردازش در طول زمان استفاده میکنیم:
while ( sleep 1 ) ; do ps -p $PID -o %cpu,%mem,rss ; done
اگر دیدید حافظه بالا میرود ممکن است به خاطر تنظیمات VM شما باشد. اگر تنظیمات خاصی برای حافظه در JVM تنظیم نکردید، تنظیمات پیش فرض آن خواهد بود. برای گرفتن تنظیمات پیش فرض، از دستور زیر استفاده کنید:
java -XX:+PrintFlagsFinal -version | grep -i HeapSize
اگر آن در محدودهای که مورد درخواستتان است نبود، لازم است تنظیمات حافظه را برای JVM وارد کنید. شما میتوانید سایز کمینه و بیشینه را برای حافظه به این شکل وارد کنید:
java -Xms128m -Xmx256m
حالا که تنظیمات حافظه درست شد و شما میتوانید مصرف حافظه را در این فرآیند مشاهده کنید. ممکن است مشاهده کنید که حافظه در گذر زمان افزایش پیدا میکند.برای اینکه از علت آن بیشتر آگاه شویم میتوانیم از هیستوگرام نمونههای اشیا با استفاده از دستور زیر کمک بگیریم:
jmap -histo $PID
اگر این اطلاعات کافی نبود میتوان با دستور زیر heap dump ها را دریافت کرد:
jmap -dump:format=b,file=/tmp/dump1.hprof $PID
معمولا دو heap dump میگیریم و آنها را با استفاده از دستور زیر مقایسه میکنیم:
jhat -baseline /tmp/dump1.hprof /tmp/dump2.hprof
این دستور یک HTTP سرور را فعال میکند که میتوانید از آن برای پیدا کردن اختلاف دو heap dump استفاده کنید. به طور پیش فرض، این HTTP سرور روی پورت ۷۰۰۰ اجرا میشود که میتوانید روی مرورگر آن را مشاهده کنید.
اگر پشت یک فایروال قرار دارید اما دسترسی به ssh دارید میتوانید به این شکل به پورت دسترسی پیدا کنید:
ssh -L 7000:localhost:7000 $HOST
اگر به انتهای صفحه اول اسکرول کنید این لینکها را مشاهده میکنید:
Show instance counts for all classes (excluding platform)
که به شما تمام نمونههای جدیدی که بین heapهای مختلف وجود دارد را نشان میدهد. به این ترتیب به شما ایده میدهد که نشتی حافظه از کجا میتواند باشد. در زیر یک تصویر از آن نشان داده شده است:
پس در این مقاله یک خلاصه سریع و مختصر از دستورات و خطوط فرمانی که برای تشخیص نشت حافظه مورد نیاز است و اغلب فراموش میشوند جمعآوری گردید. امیدواریم مفید بوده باشد. نظرات خود را با ما در میان بگذارید.
منابع:
اگر دچار مشکل شدید از سینتکس زیر استفاده کنید:
jhat -baseline /tmp/dump1.hprof#1 /tmp/dump2.hprof#2
همچنین فراموش نکنید که با اجرای jhat، در انتها باید پیام server is ready را ببینید نه killed!
تا بتوانید از طریق مرورگر و آدرس localhost:7000، گزارش مربوطه رامشاهده نمایید
در اجرای jhat، ممکنه با خطای زیر مواجه شوید
java.lang.OutOfMemoryError: Java heap space
در این صورت، لازم است کمی از حافظه دوست داشتنی ماشینتون رو به صورت زیر بهش اختصاص بدین
jhat -J-mx3g -baseline/tmp/dump1.hprof /tmp/dump2.hprof
به جای 3 گیگ (3g)، میزان حافظه ای که فکر می کنید مناسب باشه رو قرار بدید.