Heap Dump: چیست، تحلیل heap و رفع نشت حافظه

نویسنده: IT Sectr منتشر شده: 2026-05-07 زمان مطالعه: 10 دقیقه

Heap Dump (dump heap) — تصویری از حافظه پویای برنامه است که اطلاعات کامل درباره تمام اشیاء زنده را شامل می‌شود: کلاس‌ها، اندازه‌ها، ارجاعات متقابل و دسترسی از گره‌های ریشه (GC roots). Heap Dump ابزار اصلی تحلیل نشت حافظه و بهینه‌سازی مصرف منابع است. به گفته Android Developers، تحلیل heap dumpها امکان تشخیص تا 95% نشت‌های حافظه را فراهم می‌کند، از جمله ارجاعات چرخه‌ای، listenerهای فراموش شده و ارجاعات استاتیک آزاد نشده.

نکات اصلی

  • Heap Dump — تصویری از تمام حافظه پویای برنامه با اطلاعات درباره هر شیء و ارجاعات بین آنها.
  • Android Studio Memory Profiler امکان گرفتن heap dump در زمان واقعی برای برنامه‌های Java و Kotlin را فراهم می‌کند.
  • Xcode Instruments ابزار Allocations را برای ایجاد و تحلیل heap dumpها در iOS/macOS ارائه می‌دهد.
  • Shallow و retained size معیارهای کلیدی هستند: shallow اندازه خود شیء، retained اندازه شیء به علاوه تمام اشیائی که توسط آن نگهداری می‌شوند.
  • تحلیل heap dump شامل جستجوی dominator tree، بزرگترین retained objects و کوتاهترین مسیرها به GC roots است.

Heap dump چیست و چرا به آن نیاز داریم

Heap dump یک dump کامل از heap ماشین مجازی است — ناحیه حافظه‌ای که تمام اشیاء ایجاد شده پویا در آن قرار می‌گیرند. در Java و Kotlin این Dalvik/ART در Android است، در Swift و Objective-C — heap مدیریت شده توسط ARC در iOS. Heap dump هر شیء، کلاس، اندازه، فیلدها، ارجاعات به اشیاء دیگر و پرچم‌های دسترسی از GC roots (متغیرهای پشته، فیلدهای استاتیک، ارجاعات JNI) را ثبت می‌کند.

هدف اصلی heap dump تشخیص نشت حافظه است. نشت زمانی رخ می‌دهد که برنامه به نگهداری ارجاعات به اشیایی که دیگر مورد نیاز نیستند ادامه می‌دهد و از جمع‌آوری آنها توسط garbage collector (یا آزادسازی از طریق ARC) جلوگیری می‌کند. دلایل معمول: listenerهای رویداد که هنگام نابودی activity لغو نشده‌اند؛ singletonهایی با ارجاعات به context؛ closures که self را گرفته‌اند؛ مجموعه‌های استاتیک که داده‌ها بدون حذف به آنها اضافه می‌شوند. Heap dump تصویر دقیقی ارائه می‌دهد: کدام اشیاء «زنده» هستند، کدام یک اضافی هستند و دقیقاً چه کسی به آنها ارجاع می‌دهد.

به گفته Google I/O، بیش از 60% گزارش‌های crash برنامه‌های Android با OutOfMemoryError مرتبط هستند و در 80% موارد علت اصلی نشت حافظه‌ای است که از طریق heap dump قابل تشخیص است. برای برنامه‌های iOS وضعیت مشابه است: نشت‌های ناشی از retain cycles یکی از دلایل رایج خرابی‌هایی است که از طریق Allocations instrument در Xcode شناسایی می‌شوند.

چه زمانی به heap dump نیاز است

Heap dump باید در علائم زیر انجام شود: برنامه حافظه را به صورت خطی در اقدامات تکراری مصرف می‌کند (رفتن و برگشتن بین صفحه‌ها)؛ پس از پایان کار صفحه، حافظه به سطح اولیه بازنمی‌گردد؛ OutOfMemoryError یا اخطارهای memory warning در iOS رخ می‌دهد؛ برنامه به دلیل تجاوز از محدودیت حافظه خاتمه می‌یابد (EXC_RESOURCE_RESOURCE در iOS). جمع‌آوری منظم heap dumpها بخشی از پروتکل فرهنگ مهندسی در پروژه‌های بزرگ موبایل مانند Instagram و Spotify است.

Heap dump در Android Studio: دریافت و تحلیل

Android Studio Memory Profiler را ارائه می‌دهد — ابزاری داخلی برای گرفتن heap dump در زمان واقعی. از طریق View → Tool Windows → Profiler قابل دسترسی است. پس از راه‌اندازی برنامه، جلسه را انتخاب کنید، به تب Memory بروید و Dump Java Heap را کلیک کنید. Android Studio برنامه را متوقف می‌کند، dump heap ART را اجرا می‌کند و نتیجه را برای تحلیل بارگذاری می‌کند. فایل dump دارای فرمت .hprof — استاندارد HPROF سازگار با اکثر تحلیلگرهای حافظه است.

پس از بارگذاری dump، Android Studio جدولی از اشیاء با ستون‌ها نمایش می‌دهد: Allocations (تعداد نمونه‌ها)، Native Size (حافظه خارج از heap ART)، Shallow Size (حافظه خود شیء)، Retained Size (حافظه شیء با کل زیرگراف). فیلتر بر اساس نام کلاس، مرتب‌سازی بر اساس retained size و جستجو بر اساس بسته‌ها به شما امکان می‌دهد quickly مناطق مشکل‌دار را پیدا کنید.

kotlin
// نشت معمولی — listener لغو نشده در onDestroy
class MainActivity : AppCompatActivity() {
    private val sensorManager by lazy {
        getSystemService(SENSOR_SERVICE) as SensorManager
    }
    private val listener = MySensorListener()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        sensorManager.registerListener(listener,
            sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
            SensorManager.SENSOR_DELAY_NORMAL)
    }

    override fun onDestroy() {
        super.onDestroy()
        // ❌ sensorManager.unregisterListener(listener) فراموش شده
        // → Activity توسط GC جمع‌آوری نمی‌شود، heap dump نشت را نشان می‌دهد
    }
}

تحلیل dominator tree در Android Studio

تب Dominator Tree اشیائی را نشان می‌دهد که بیشترین مقدار حافظه را نگه می‌دارند. اگر شیء از dominator tree حذف شود، تمام حافظه‌ای که نگه می‌دارد برای جمع‌آوری در دسترس می‌شود. این ابزار کلیدی است: به جای مشاهده هزاران شیء، روی 10-20 شیء تمرکز می‌کنید که 80-90% حافظه را کنترل می‌کنند. به گفته Google، تحلیل dominator tree مؤثرترین راه برای یافتن نقطه نشت است که زمان تحلیل را از ساعت‌ها به دقیقه کاهش می‌دهد.

Heap dump در Xcode Instruments: Allocations و Leaks

Xcode Instruments دو ابزار برای کار با heap dump ارائه می‌دهد: Allocations — گرفتن dump heap با نمودار مصرف در زمان واقعی؛ Leaks — جستجوی خودکار نشت‌ها از طریق تحلیل retain cycles. Allocations تمام اشیاء در heap، اندازه آنها، تعداد ایجاد (allocations) و آزادسازی (deallocations) را نمایش می‌دهد. تفاوت بین تعداد ایجاد و آزادسازی برای یک کلاس خاص نشان‌دهنده نشت بالقوه است.

گرفتن heap dump در Allocations با دکمه Snapshot Memory انجام می‌شود — ابزار برنامه را متوقف می‌کند و dump کامل می‌گیرد. پس از آن نمایش‌های استاندارد در دسترس هستند: لیست اشیاء بر اساس کلاس، درخت فراخوانی (call tree) برای هر شیء و مولد گزارش. برخلاف Android Studio، Xcode از .hprof استفاده نمی‌کند، بلکه داده‌ها را در قالب اختصاصی خود .trace سازگار با Instruments ذخیره می‌کند.

swift
// نشت معمولی iOS — retain cycle از طریق closure
class NetworkManager {
    var onComplete: ((Data) -> Void)?

    func startRequest() {
        // ❌ Closure self را گرفته — retain cycle
        onComplete = { data in
            self.process(data)
        }
    }
    func process(_ data: Data) {}
}

Leaks instrument به طور خودکار retain cycles و نشت‌ها را از طریق تحلیل گراف ارجاع تشخیص می‌دهد. اشیاء نشتی را با آیکون بنفش علامت‌گذاری می‌کند و مسیر ریشه (GC root) را نشان می‌دهد. برای رفع retain cycle کافی است [weak self] یا [unowned self] به closure اضافه کنید. اجرای منظم Leaks instrument یک مرحله اجباری CI در تیم‌هایی است که از Swift برای توسعه iOS استفاده می‌کنند.

swift
// رفع — ارجاع ضعیف به self
onComplete = { [weak self] data in
    guard let self else { return }
    self.process(data)
}

Shallow size, retained size و dominator tree

برای تحلیل صحیح heap dump لازم است سه معیار کلیدی را درک کنید. Shallow size — حجم حافظه اشغال شده مستقیماً توسط شیء: فیلدها، هدر و ترازبندی آن. برای یک شیء Java/Kotlin معمولی shallow size 16-40 بایت است. Retained size — shallow size شیء به علاوه مجموع shallow size تمام اشیائی که فقط از طریق این شیء در دسترس هستند (یعنی پس از حذف آن به زباله تبدیل می‌شوند). دقیقاً retained size تأثیر واقعی شیء بر مصرف حافظه را نشان می‌دهد.

معیارتوضیحمثال
Shallow sizeاندازه خود شیء بر حسب بایتBitmap (100×100) = 40 016 B
Retained sizeShallow size + هر آنچه نگه می‌داردActivity با View Tree = 2-5 MB
Deep sizeRetained size + اشیاء تودرتو از گراف‌های دیگرScrollView با آداپتر = 10-50 MB

Dominator tree — ساختاری که در آن هر شیء به «مسلط» خود اشاره می‌کند — شیئی که دسترسی به آن را کنترل می‌کند. اگر مسلط حذف شود، تمام اشیاء زیردرخت آن زباله می‌شوند. تحلیل dominator tree سریعترین راه برای یافتن شیئی است که بیشترین حافظه را نگه می‌دارد. به گفته Eclipse MAT (Memory Analyzer Tool)، 90% نشت‌ها از طریق مشاهده 20 شیء برتر dominator tree در عرض 5 دقیقه شناسایی می‌شوند.

تحلیل نشت حافظه از طریق heap dump

فرآیند تحلیل نشت از طریق heap dump از چند مرحله تشکیل شده است. مرحله 1: عملی را انجام دهید که باید حافظه را آزاد کند (صفحه را ببندید، عملیات را تمام کنید). مرحله 2: GC را فراخوانی کنید (System.gc() در Android، snapshot اجباری در Xcode) و heap dump بگیرید. مرحله 3: اشیائی را پیدا کنید که باید نابود شده باشند (مثلاً نمونه Activity پس از finish). مرحله 4: برای شیء مشکوک Path to GC Roots را اجرا کنید — زنجیره ارجاعاتی که شیء را زنده نگه می‌دارد. آخرین ارجاع در زنجیره علت نشت است.

مسیر به GC Roots (Path to GC Roots)

تابع Path to GC Roots در Android Studio Profiler، Eclipse MAT و Xcode Instruments در دسترس است. کوتاهترین زنجیره ارجاعات از GC root تا شیء مشکل‌دار را نشان می‌دهد. با حذف ارجاعات ضعیف (weak) و نرم (soft)، فقط ارجاعات قوی (strong) — آنهایی که واقعاً مانع جمع‌آوری می‌شوند — باقی می‌مانند. طبق آمار Square Engineering، 70% نشت‌ها در برنامه‌های Android تنها توسط دو الگو ایجاد می‌شوند: ارجاعات استاتیک به Activity یا Context و listenerهای ثبت شده اما لغو نشده.

kotlin
// مثال نشت از طریق ارجاع استاتیک
object AppCache {
    private val cache = mutableMapOf<String, Any>()

    fun storeActivityReference(activity: Activity) {
        cache["current_activity"] = activity // ❌ نشت!
    }
}

// رفع: ارجاع ضعیف
object AppCacheFixed {
    private val cache = mutableMapOf<String, WeakReference<Any>>()
}

مقایسه دو heap dump

تکنیک comparison mode — یکی از مؤثرترین روش‌های یافتن نشت‌ها است. قبل و بعد از یک عمل تکراری heap dump بگیرید (مثلاً پنج بار رفتن به صفحه و برگشتن). تعداد نمونه‌های کلاس‌های کلیدی را مقایسه کنید: اگر تعداد Activity افزایش یافته، در حالی که همه فعالیت‌ها بسته شده‌اند — این نشت است. Android Studio و Eclipse MAT از مقایسه خودکار dumpها با برجسته‌سازی تفاوت‌ها پشتیبانی می‌کنند. به گفته Google، مقایسه dumpها امکان یافتن نشت‌هایی را فراهم می‌کند که در تحلیل یکباره به دلیل انباشت اثر قابل مشاهده نیستند.

توصیه‌های عملی برای کاهش مصرف حافظه

بر اساس تحلیل heap dump در پروژه‌های واقعی، روش‌های اثبات شده بهینه‌سازی حافظه تدوین شده است. از WeakReference استفاده کنید برای کش‌ها، فراخوانی‌های برگشتی و ارجاعات به context در اشیاء طولانی‌مدت. listenerها را لغو کنید در onPause/onDestroy برای Android و deinit برای iOS. از مجموعه‌های استاتیک بزرگ خودداری کنید — اگر ضروری هستند، از LruCache با محدودیت اندازه استفاده کنید. Bitmapها را بهینه کنید: تصاویر را با inSampleSize مناسب بارگذاری کنید، از Glide یا Picasso با کش دیسکی استفاده کنید.

پروفایلینگ حافظه در فرآیند توسعه

گرفتن منظم heap dump را در CI قرار دهید. وظیفه‌ای را پیکربندی کنید که تست‌های UI ابزاری را اجرا می‌کند، سناریوهای کلیدی کاربر را انجام می‌دهد و heap dump را با baseline مقایسه می‌کند. اگر retained size بیش از 5% از baseline افزایش یافته باشد، build به عنوان regression علامت‌گذاری می‌شود. این رویکرد در Airbnb، Uber و سایر شرکت‌های با الزامات کیفیت بالا استفاده می‌شود. به گفته Uber Engineering، پیاده‌سازی تحلیل خودکار heap dump در CI تعداد باگ‌های مرتبط با حافظه را 70% در یک چهارم کاهش داد.

groovy
// مثال task Gradle برای heap dump خودکار در CI
task profileMemory(type: Exec) {
    commandLine 'adb', 'shell',
        'am start -n com.example/.MainActivity'
    // در انتظار بارگذاری
    doLast {
        exec { commandLine 'adb', 'shell',
            'am broadcast -a com.example.DUMP_HEAP' }
    }
}

سوالات متداول

تفاوت بین shallow size و retained size چیست؟

Shallow size — اندازه خود شیء (فیلدها + هدر). Retained size — اندازه شیء به علاوه تمام اشیائی که پس از حذف آن به زباله تبدیل می‌شوند. Retained size شاخص اصلی تأثیر شیء بر مصرف حافظه است.

چگونه روی دستگاه فیزیکی Android heap dump بگیریم؟

از طریق Android Studio Profiler دستگاه و فرآیند را انتخاب کنید، Dump Java Heap را کلیک کنید. جایگزین — از طریق خط فرمان: adb shell am dumpheap PID /sdcard/dump.hprof، سپس adb pull.

چرا heap dump می‌تواند بسیار بزرگ باشد (500 MB+)؟

Heap dump تمام اشیاء زنده را شامل می‌شود. اگر برنامه از کش‌ها، Bitmapها استفاده می‌کند یا داده‌های بزرگ پردازش می‌کند، dump می‌تواند به صدها مگابایت برسد. بر اساس کلاس فیلتر کنید یا از Eclipse MAT برای بارگذاری فقط ایندکس استفاده کنید.

آیا می‌توان heap dump را بدون Android Studio تحلیل کرد؟

بله، از Eclipse MAT (Memory Analyzer Tool) استفاده کنید — ابزاری رایگان برای تحلیل .hprof. از dominator tree، path to GC roots، مقایسه dumpها و جستجوی خودکار نشت از طریق Leak Suspects Report پشتیبانی می‌کند.

آیا heap dump عملکرد برنامه را کاهش می‌دهد؟

خود dump — بله، زیرا جمع‌آوری dump تمام رشته‌ها را متوقف می‌کند (stop-the-world). بدون dump — خیر. Dump را در شرایط کنترل‌شده (محیط تست، CI) انجام دهید، نه در محیط تولید.

خلاصه

  • Heap Dump — تصویر کامل heap برنامه با اطلاعات درباره هر شیء و ارتباطات بین آنها.
  • Android Studio Memory Profiler و Xcode Instruments Allocations — ابزارهای اصلی گرفتن dump.
  • Shallow size — اندازه خود شیء؛ retained size — اندازه شیء با کل زیرگراف وابستگی‌ها.
  • Dominator tree — درخت مسلط‌ها که اشیاء کنترل‌کننده بیشترین حافظه را نشان می‌دهد.
  • Path to GC Roots — زنجیره ارجاعات قوی که شیء را از جمع‌آوری زباله بازمی‌دارد.
  • مقایسه دو heap dump (قبل/بعد از عمل) — قابل‌اطمینان‌ترین روش تشخیص نشت.
  • خودکارسازی گرفتن و تحلیل heap dumpها در CI از regressions حافظه در مرحله توسعه جلوگیری می‌کند.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید