فرض کن تو یه کارگاه بزرگ و مدرن (همون حافظه Heap) داری یه پروژه خفن میسازی. برای هر ابزار یا قطعه‌ای که نیاز داری، فقط کافیه یه فرمان بدی (کلمه کلیدی new) تا اون قطعه سریعاً برات ساخته بشه. تو زبان ‌های مثل C یا ++C، وقتی کارت با اون قطعه تموم میشه، باید خودت دستی ببریش بیرون و نابودش کنی (free یا delete)؛ وگرنه انقدر خرت‌ و پرت تو کارگاه جمع میشه که دیگه جای سوزن انداختن نمیمونه و کارگاه تعطیل میشه (همون خطای پر شدن حافظه یا Memory Leak). اما تو جاوا، یه ربات نامرئی و خیلی دقیق تو پس‌ زمینه در حال گشت‌زنیه. این ربات مدام کارگاه رو اسکن میکنه؛ هر شیء (Object) که دیگه تو دستت نیست و هیچ سیمی (Reference) هم از برنامه اصلی بهش وصل نیست رو پیدا میکنه و بی‌سروصدا پودرش میکنه تا فضا برای ساخت اشیای جدید باز بشه. این ربات هوشمند، همون Garbage Collector (GC) یا زباله‌ روب جاواست! حالا بیا ببینیم زیر کاپوت این ربات دقیقاً چه خبره و چطوری کار میکنه.

زباله‌روب از کجا می‌فهمه چی زباله‌ست؟

زباله روب جاوا برای پیدا کردن زباله‌ ها از یه مفهوم ساده استفاده میکنه: "آیا کسی هنوز به این شیء دسترسی داره یا نه؟" به این کار میگن بررسی Reachability (قابل دسترس بودن). اگر یک شیء تو حافظه باشه ولی هیچ متغیر یا رفرنس فعالی تو برنامه بهش اشاره نکنه، یعنی اون شیء دیگه به درد نمیخوره، ارتباطش با برنامه قطع شده و رسماً تبدیل به زباله شده.

۳ قدم اصلی برای پاکسازی حافظه (Mark, Sweep, Compact)

زباله‌روب جاوا معمولاً کارش رو تو سه مرحله اصلی انجام میده:

  • علامت‌گذاری (Marking): تو این مرحله، GC کل حافظه رو میگرده و روی تمام اشیایی که هنوز دارن استفاده میشن (زنده هستن) یه تیک میزنه. زمان این مرحله بستگی به تعداد اشیای زنده داره.
  • جاروکشی (Sweeping): حالا نوبت پاک‌سازی است! GC تمام اشیایی که تو مرحله قبل تیک نخورده بودن رو به عنوان زباله میشناسه، از حافظه پاکشون میکنه و جاشون رو خالی میکنه.
  • فشرده‌سازی (Compacting): وقتی اشیای زاید پاک میشن، حافظه مثل یه پنیر سوئیسی سوراخ‌ سوراخ و تکه‌ تکه میشه (Fragmentation). برای اینکه جاوا بتونه اشیای بزرگِ جدید رو راحت‌تر تو حافظه جا بده، GC میاد اشیای زنده رو هل میده کنار هم تا فضای خالیِ یکپارچه و بزرگی به وجود بیاد.

ترفند هوشمندانه جاوا: حافظه نسلی (Generational GC)

طراحان جاوا متوجه یه قانون خیلی جالب و طلایی شدن: "بیشتر اشیاء توی جاوا خیلی زود میمیرن!" (مثلاً متغیر هایی که داخل یه متد یا حلقه میسازی و به محض تموم شدن متد، کارشون تموم میشه). برای همین، اومدن حافظه Heap رو به چند تا «نسل» یا بخش تقسیم کردن تا GC مجبور نباشه هر دفعه کل حافظه رو بگرده:

  • نسل جوان (Young Generation): تمام اشیای جدید اینجا متولد میشن. این بخش تند تند پر میشه و زباله ‌روب خیلی سریع و مکرر میاد اینجا رو تمیز میکنه (به این کار میگن Minor GC).
  • نسل پیر (Old / Tenured Generation): اگه یه شیء جون‌سخت باشه و چند بار از دست زباله ‌روب نسل جوان قسر در بره، ارتقا پیدا میکنه و میاد تو نسل پیر! اینجا اشیایی هستن که برنامه برای مدت طولانی بهشون نیاز داره (مثل کش‌ ها یا کانکشن‌ های دیتابیس). پاکسازی این بخش کمتر اتفاق میفته ولی چون بزرگه، وقت بیشتری میگیره (بهش میگن Major GC).

انواع زباله‌روب‌ ها در جاوا 

جاوا تو نسخه‌های مختلفش، ربات‌ های متفاوتی رو معرفی کرده که هر کدوم برای یه سناریوی خاص طراحی شدن. تو جدول زیر میتونی یه مقایسه سریع ازشون ببینی:

Serial GC : فقط از یک Thread برای پاکسازی استفاده میکنه. موقع کار، کل برنامه متوقف میشه.

کاربرد : برنامه‌های کوچیک روی سیستم‌ های تک‌ هسته‌ای.

Parallel GC : از چندین Thread همزمان برای پاکسازی استفاده میکنه تا کار زودتر تموم بشه

کاربرد : برنامه‌هایی که پردازش‌های سنگین دارن و میخوایم بالاترین توان (Throughput) رو داشته باشیم.

G1 GC (Garbage First) : حافظه رو به بلوک‌های کوچیک تقسیم میکنه و اول میره سراغ بلوک‌هایی که بیشترین زباله رو دارن.

کاربرد : زباله‌روب پیش‌فرض جاوا (از نسخه ۹ به بعد). عالی برای سرورها و برنامه‌های بزرگ.

ZGC (Z Garbage Collector) : بی‌ نهایت سریعه! طوری همزمان با برنامه کار میکنه که وقفه تو اجرای برنامه کمتر از ۱ میلی‌ثانیه بشه.

کاربرد : سیستم‌ های مالی یا حساس که حتی یک صدم ثانیه توقف (Pause time) هم براشون فاجعه‌ست.

جمع بندی

اگه بخوایم کل داستان زباله‌ روب جاوا رو تو چند تا نکته کلیدی خلاصه کنیم، به این نتیجه میرسیم:

  • مدیریت خودکار و آسودگی خیال: GC بار سنگین و پرخطرِ مدیریت دستی حافظه رو از دوش ما برداشته تا تمرکزمون فقط روی نوشتن منطق و فیچرهای برنامه باشه، نه ترس از جا موندنِ یه متغیر تو حافظه!
  • مکانیزم هوشمند و بهینه: این ربات با استفاده از روشِ ۳ مرحله‌ای (علامت‌گذاری، پاکسازی، فشرده‌سازی) و ایده خلاقانه «تقسیم حافظه به نسل‌های جوان و پیر»، کاری کرده که پاکسازی با بیشترین سرعت و کمترین وقفه (Pause Time) انجام بشه.
  • تنوع ابزارها برای نیازهای مختلف: جاوا دست ما رو باز گذاشته. همون‌طور که دیدیم، برای هر پروژه‌ای یه زباله‌روب مخصوص وجود داره؛ از Serial GC برای کارهای کوچیک گرفته تا ZGC برای سیستم‌های فوق‌سریع و حساس.
  • مسئولیت همچنان با ماست! GC جادوگر نیست. اگه رفرنسِ اشیای بی‌ استفاده رو قطع نکنیم (مثلاً تو مجموعه ‌های استاتیک نگهشون داریم)، این ربات فریب میخوره و نمیتونه پاکشون کنه؛ نتیجه‌اش هم چیزی نیست جز نشت حافظه (Memory Leak) و در نهایت از کار افتادن برنامه. در نهایت، شناخت دقیق نحوه کار Garbage Collector دقیقاً همون چیزیه که مرز بین یه برنامه ‌نویس معمولی جاوا و یه برنامه‌ نویس حرفه‌ای (Senior) رو مشخص میکنه. کسی که میدونه زیر کاپوت ماشین مجازی جاوا (JVM) چه خبره، کد هایی مینویسه که هم سریع‌تر اجرا میشن و هم منابع سرور رو بهینه‌ تر مصرف میکنن.