برای درک میزان استفاده از حافظه در اندروید، باید از چندین دیدگاه مختلف به سیستم نگاه کنید، از اشیاء سطح بالای جاوا گرفته تا صفحات هسته سطح پایین.
صخره عملکرد
استفاده از حافظه به خودی خود چیز خوب یا بدی نیست؛ مهم این است که از حافظه برای چه کاری استفاده میکنید. با این حال، وقتی به محدودیت حافظه موجود در یک دستگاه نزدیک میشوید، در نهایت "از پرتگاه عملکرد سقوط میکنید".

وقتی از پرتگاه دور هستید، اضافه کردن مقدار کمی حافظه مصرفی (مثلاً ۵۰ مگابایت) ممکن است تأثیر محسوسی بر عملکرد نداشته باشد. با این حال، وقتی رم موجود تمام میشود، به پرتگاه میرسیم. در این مرحله، سیستم عامل باید شروع به صفحهبندی حافظه و از بین بردن فرآیندها برای آزاد کردن فضا کند. فراتر از این پرتگاه، حتی افزایش اندک در استفاده از حافظه میتواند منجر به "ضربه شدید" قابل توجهی شود، که در آن دستگاه پاسخگو نیست یا به نظر میرسد که به دلیل از بین رفتن فرآیندهای حیاتی، مجدداً راهاندازی میشود.
پشته اندروید
هر لایه از پشته اندروید، نمای منحصر به فرد خود از حافظه را دارد:

- برنامهها (جاوا/کاتلین) : توسعهدهندگان در درجه اول اشیاء جاوا را که در حافظه هیپ جاوا تخصیص داده شدهاند، مشاهده میکنند.
- زمان اجرای اندروید (ART) : ART با استفاده از صفحات حافظه مجازی از هسته، هیپ جاوا/کاتلین را مدیریت میکند. قبلاً با نام Dalvik شناخته میشد (این اصطلاحات گاهی اوقات به جای یکدیگر استفاده میشوند).
- هسته لینوکس : هسته، حافظه را به صورت صفحات فیزیکی و مجازی میبیند. به طور سنتی، این صفحات ۴ کیلوبایت هستند، اما اندروید از صفحات ۱۶ کیلوبایتی نیز پشتیبانی میکند. هسته چیزی در مورد «اشیاء جاوا» نمیداند.
اگر میخواهید حافظه را بهینهسازی کنید، یا باید در لایه خودتان بهینهسازی را انجام دهید (مثلاً بارگذاری تعداد کمتری بیتمپ) یا لایههای زیرین خود را درک کنید تا ببینید تخصیصهای سطح بالای شما چگونه به استفاده از صفحه فیزیکی تبدیل میشوند.
انواع حافظه: ناشناس در مقابل فایل پشتیبان
قبل از اینکه به نحوه بازیابی حافظه توسط سیستم عامل بپردازیم، باید دو دسته اساسی صفحات حافظه در لینوکس را درک کنید:
- حافظه ناشناس (
anon) : حافظهای که توسط فایلی در حافظه پشتیبانی نمیشود . این شامل حافظهای است که توسطmallocدر C/C++ (مانند تخصیصدهنده Scudo) و حافظهای که برای اشیاء جاوا در پشته Java/Kotlin اختصاص داده شده است. از آنجا که این حافظه هیچ فایل منبعی برای بازگشت به آن ندارد، سیستمعامل باید یا آن را در RAM نگه دارد یا در صورت فشار، آن را فشرده کرده و به ZRAM منتقل کند. - حافظه با پشتیبانی فایل (
file-backed memory) : حافظهای که مستقیماً از یک فایل روی حافظه نگاشت میشود. این شامل کد اجرایی (فایلهای DEX، کتابخانههای.so) و فونتها میشود.
فایلهای نگاشتشده در حافظه (mmap)
اندروید از mmap برای نگاشت حافظهی فایل-پشتیبانیشده و ناشناس به فضای آدرس یک فرآیند استفاده میکند.
هنگام برخورد با حافظهی فایل-بکآپ، صفحات به موارد زیر طبقهبندی میشوند:
- پاکسازی حافظه : صفحاتی که از یک فایل نگاشت شدهاند و تغییر نکردهاند. اگر سیستم به حافظه بیشتری نیاز داشته باشد، هسته میتواند به سادگی این صفحات را حذف کند، زیرا بعداً میتوانند مستقیماً از فایل موجود در حافظه دوباره بارگذاری شوند.
- حافظه کثیف : صفحاتی که توسط فرآیند تغییر یافتهاند. این صفحات را نمیتوان حذف کرد؛ آنها مانند حافظه ناشناس رفتار میکنند و باید در RAM نگهداری شوند یا به ZRAM منتقل شوند.
اندروید فرمتهای فایلی (مانند DEX) را ترجیح میدهد که با نگاشت حافظه سازگار باشند و به سیستم اجازه دهند به راحتی حافظه خالی را تحت فشار بازیابی کند. از آنجا که حافظه ناشناس و کثیف را نمیتوان به سادگی حذف کرد، حافظه خصوصی کثیف/ناشناس با حجم بالا علت اصلی کندی سیستم و مداخلات Low Memory Killer (LMK) است. اگر برنامه شما از حافظه خصوصی کثیف زیادی استفاده میکند، شما مستقیماً در کاهش عملکرد نقش دارید.
مدل فرآیند زیگوت
اندروید با استفاده از فرآیندی به نام Zygote هزینه شروع برنامههای جدید را به حداقل میرساند.
- Zygote هنگام بوت شدن سیستم شروع به کار میکند و کلاسها و منابع رایج چارچوب را از قبل در حافظه خود بارگذاری میکند. از دیدگاه هسته، این یک حافظه کثیف ناشناس است، اما این حافظه مختص فرآیند Zygote است.
- وقتی یک برنامه جدید شروع میشود، سیستم فرآیند Zygote را منشعب میکند .
- فرآیند فرزند جدید، حافظهی Zygote را با استفاده از یک نگاشت مشترک با مفاهیم کپی-هنگام-نوشتن (COW) به ارث میبرد.

تا زمانی که فرآیند فرزند فقط حافظهای را که از Zygote به ارث برده است، میخواند، صفحات حافظه فیزیکی بین همه فرآیندها مشترک باقی میمانند. وقتی یک فرآیند فرزند یک صفحه مشترک را تغییر میدهد، هسته به طور شفاف یک کپی خصوصی از آن صفحه برای فرآیند ایجاد میکند. این مدل به بسیاری از فرآیندها اجازه میدهد تا بخش بزرگی از حافظه خود - به ویژه کد چارچوب و منابع - را به اشتراک بگذارند و به طور قابل توجهی فضای کلی حافظه سیستم را کاهش دهند.
RSS، PSS و USS
از آنجا که حافظه به شدت بین فرآیندها - عمدتاً از طریق مدل Zygote - به اشتراک گذاشته میشود، سه روش اصلی برای محاسبه میزان استفاده از حافظه توسط یک فرآیند وجود دارد:

- RSS (اندازه مجموعه ساکن) : تعداد کل صفحاتی که فرآیند در RAM دارد. این مقدار، میزان استفاده را بیش از حد تخمین میزند زیرا صفحات مشترک را چندین بار (یک بار برای هر فرآیندی که آنها را به اشتراک میگذارد) شمارش میکند.
- PSS (اندازه مجموعه متناسب) : کل مقدار حافظه منحصر به فرد برای فرآیند، به علاوه سهم متناسب آن از حافظه مشترک. اگر یک صفحه توسط 5 فرآیند به اشتراک گذاشته شود، هر فرآیند برای 1/5 آن صفحه هزینه دریافت میکند.
- USS (اندازه مجموعه منحصر به فرد) : مقدار حافظهای که مختص به فرآیند است. این حافظهای است که در صورت از بین رفتن فرآیند به سیستم بازگردانده میشود.
از کدام معیارها، چه زمانی استفاده کنیم؟
انتخاب معیار مناسب برای حافظه بستگی به این دارد که چه چیزی را میخواهید اندازهگیری کنید و در چه محیطی آن را میسنجید.
| متریک | بهترین برای | نقاط قوت کلیدی | ایراد اصلی |
|---|---|---|---|
| پیاساس | اسنپشاتهای حافظه در سطح سیستم | حافظه مشترک را به طور دقیق متناسب میکند. جمع PSS برابر با کل حافظه استفاده شده است. | بر اساس سایر فرآیندهای در حال اجرا نوسان دارد. برای مقایسه یک برنامه خاص در طول زمان مناسب نیست. |
| آر اس اس | ردیابی یک برنامهی خاص در طول زمان، تلهمتری میدانی | پایدار، مستقل از سایر فرآیندها. جمعآوری سریع و ارزان. | کل استفاده را بیش از حد تخمین میزند زیرا حافظه مشترک را چندین بار شمارش میکند. |
| ناو هواپیمابر یواساس | ارزیابی تأثیر از بین بردن یک فرآیند | دقیقاً نشان میدهد که در صورت خاتمه برنامه، چه مقدار حافظه آزاد میشود. | حافظه مشترک را کاملاً نادیده میگیرد. |
PSS (اندازه مجموعه متناسب)
- بهترین کاربرد: گرفتن اسنپشات کامل از حافظه سیستم از یک دستگاه خاص در یک زمان معین.
- چرا: PSS این خاصیت ریاضی مفید را دارد که مجموع PSS برای تمام فرآیندهای در حال اجرا برابر با کل حافظه استفاده شده توسط فرآیندهای سیستم است. این سیستم حافظه مشترک را بدون شمارش مجدد، به طور کامل تقسیم میکند.
- چه زمانی باید از آن اجتناب کرد: شما نباید از PSS برای مقایسه یک فرآیند خاص در دو اسنپشات مختلف، در زمانهای مختلف یا در دستگاههای مختلف استفاده کنید. از آنجا که PSS به تعداد فرآیندهای دیگری که در حال حاضر صفحات را با فرآیند شما به اشتراک میگذارند بستگی دارد، PSS برنامه شما میتواند نوسان داشته باشد، حتی اگر رفتار واقعی برنامه شما کاملاً بدون تغییر باقی بماند.
RSS (اندازه مجموعه ساکن)
- بهترین برای: ردیابی میزان استفاده از حافظه یک برنامه در طول زمان، در طول سفرهای بحرانی کاربر (CUJ) مختلف، یا مقایسه بین نسخههای برنامه. همچنین کاربردیترین انتخاب برای اندازهگیری از راه دور میدانی است.
- چرا: RSS از PSS پایدارتر است. صرف نظر از اینکه برنامههای دیگر چه کاری انجام میدهند، اطلاعاتی در مورد حافظهای که در فرآیند شما نگاشت شده است به شما میدهد. علاوه بر این، جمعآوری RSS ارزان است. اندازهگیری PSS یا USS نیاز به اسکن ساختارهای پیچیده مدیریت حافظه هسته و به دست آوردن قفلها دارد که اگر به طور مکرر جمعآوری شوند، میتوانند باعث مشکلات عملکرد سیستم (مانند اختلال در رابط کاربری) شوند.
- بهترین روشهای اندازهگیری میدانی: هنگام جمعآوری دادهها از دستگاههای موجود در طبیعت، معمولاً بهتر است RSS ناشناس + swap (ZRAM) را اندازهگیری کنید.
- چرا فقط ناشناس؟ صفحات فایل پشتیبان (مانند کد، منابع برنامه، فونتها یا سایر فایلهای نگاشت شده در حافظه) میتوانند در هر زمانی توسط هسته به دلیل فشار حافظه پنهان در کل سیستم حذف شوند. گنجاندن صفحات فایل در معیارها برای ردیابی یک برنامه خاص، نویزهایی را از تصمیمات مدیریت حافظه سیستم عامل ایجاد میکند که ممکن است ناشی از فشار حافظه از برنامههای دیگر یا سیستم باشد. برعکس، حافظه ناشناس (مانند هیپهای جاوا و بومی) مستقیماً توسط برنامه شما کنترل میشود.
- چرا باید swap اضافه کنیم؟ تحت فشار حافظه، سیستم عامل صفحات ناشناس را فشرده کرده و آنها را به ZRAM (swap) منتقل میکند. اگر فقط حافظه ناشناس مقیم را اندازهگیری کنید، ممکن است معیارهای شما به اشتباه "کاهش" در استفاده از حافظه را نشان دهند، صرفاً به این دلیل که سیستم تحت فشار بوده و صفحات شما را swap کرده است. اضافه کردن حافظه swapped تضمین میکند که تمام حافظه ناشناسی را که برنامه شما اختصاص داده است، چه در حال حاضر در RAM باشد و چه در ZRAM، در نظر بگیرید.
USS (اندازه مجموعه منحصر به فرد)
- بهترین کاربرد: تعیین تأثیر فوری توقف یک فرآیند بر سیستم.
- دلیل: USS به طور دقیق مقدار دقیق حافظهای را نشان میدهد که در صورت خاتمه یافتن فرآیند (برای مثال، توسط سرویس Low Memory Killer،
lmkd)، بلافاصله بازیابی و به سیستم بازگردانده میشود. - نحوه استفاده: این معیار هنگام ارزیابی فرآیندهای مداوم یا سرویسهای پسزمینه بسیار ارزشمند است. اگر در حال ارزیابی هزینه کل سیستم برای یک فرآیند پسزمینه هستید، USS دقیقاً به شما میگوید که سیستم چه مقدار حافظه را منحصراً برای زنده نگه داشتن آن فرآیند خاص قربانی میکند.