اتصال‌های سرویس و وضعیت‌های فرایند

فرایندهای برنامه در Android به‌صورت مجزا وجود ندارند. برنامه‌ها اغلب به سرویس‌های ارائه‌شده توسط برنامه‌های دیگر یا خود سیستم متکی هستند. وقتی فرایندی ازطریق اتصال سرویس به فرایند دیگری متصل می‌شود، وابستگی‌ای ایجاد می‌کند که تأثیر عمیقی بر نحوه مدیریت حافظه توسط چارچوب Android دارد.

وضعیت‌های پردازش و امتیازهای کمبود حافظه

چارچوب Android از وضعیت‌های پردازش برای پیگیری اهمیت هریک از پردازش‌های درحال اجرا استفاده می‌کند. سپس OomAdjuster از این حالت‌ها برای اختصاص دادن مقدار اصلاح امتیاز کمبود حافظه (oom_score_adj) در محدوده ۱۰۰۰- تا ۱۰۰۰ استفاده می‌کند.

oom_score_adj پایین‌تر یعنی فرایند مهم‌تر است و احتمال کمتری دارد که توسط «بستن ناشی از کمبود حافظه» (LMK) بسته شود.

وضعیت‌های معمول پردازش

جدول زیر برخی‌از رایج‌ترین حالت‌های پردازش و مقادیر oom_score_adj معمول آن‌ها را نشان می‌دهد. برای مشاهده فهرست کامل و به‌روز، به android.app.ActivityManager و com.android.server.am.psc.Constants در کد منبع Android مراجعه کنید.

وضعیت پردازش (مخفف) شرح oom_score_adj معمول
PER (دائمی) فرایندهای سیستم که باید همیشه اجرا شوند (مثلاً تلفن). -800
برتر فرایندی که کاربر درحال‌حاضر با آن تعامل دارد. 0
VIS (نمایان) فرایند دارای فعالیت نمایان است (برای مثال، پشت کادر گفتگوی نیمه‌شفاف). ۱۰۰
PERC (قابل‌درک) فرایند پس‌زمینه‌ای که کاربر از آن مطلع است (مثلاً بازپخش موسیقی). ۲۰۰
FGS فرایند میزبان «سرویس پیش‌زمینه‌ای». ۰ تا ۲۰۰ (متغیر)
BTOP (Bound Top) فرایند محدودشده توسط برنامه TOP. ۱۰۰
BFGS سرویس پیش‌زمینه‌ای محدودشده (معمولاً محدودشده به سیستم). 0
PREV (قبلی) آخرین فرایندی که کاربر قبل‌از فرایند فعلی در آن بوده است. ۷۰۰
CACHED برنامه‌های پس‌زمینه که می‌توان آن‌ها را به‌طور ایمن متوقف کرد. ۹۰۰ تا ۹۹۹

تأثیر اتصال‌های سرویس

وقتی فرایند کارخواه (مثلاً برنامه‌ای در وضعیت TOP) به سرویسی در فرایند سرور متصل می‌شود، فرایند سرور اغلب اولویت بالاتری را به‌ارث می‌برد. این کار تضمین می‌کند که سرویس تا زمانی که کارخواه به آن نیاز دارد دردسترس باقی بماند.

نموداری که فرایند A (TOP) را نشان می‌دهد که bindService()‎ را ازطریق system_server فراخوانی می‌کند،
و فرایند B را به BTOP ارتقا می‌دهد

کنترل کردن وراثت با پرچم‌های BIND

هنگام استفاده از Context.BIND_AUTO_CREATE، رفتار پیش‌فرض «وراثت» است. بااین‌حال، توسعه‌دهندگان می‌توانند بااستفاده از پرچم‌های مختلف در bindService()، نحوه تأثیرگذاری اتصال بر اهمیت فرایند هدف را کنترل کنند.

پرچم‌های کلیدی BIND برای امتیاز OOM

پرچم‌های زیر هنگام مدیریت فشار حافظه در سراسر سیستم بیشترین ارتباط را دارند:

  • BIND_AUTO_CREATE: رایج‌ترین پرچم. این کار تضمین می‌کند که فرایند سرویس شروع شود و تا زمانی که اتصال وجود دارد، فعال بماند. به‌طور پیش‌فرض، اولویت فرایند سرور را نیز ارتقا می‌دهد تا با کارخواه مطابقت داشته باشد.
  • BIND_NOT_FOREGROUND: از ارتقای فرایند سرویس هدف به اولویت زمان‌بندی پیش‌نما (اولویت CPU) جلوگیری می‌کند. بااین‌حال، همچنان اجازه می‌دهد اولویت حافظه (oom_score_adj) ارتقا یابد. این برای کارهای پس‌زمینه‌ای مفید است که نباید با واسط کاربر برای چرخه‌های واحد پردازش مرکزی رقابت کنند اما همچنان باید از متوقف شدن محافظت شوند.
  • BIND_WAIVE_PRIORITY: پرچم بسیار قوی‌ای که به سیستم دستور می‌دهد نباید بر اولویت زمان‌بندی یا مدیریت حافظه فرایند هدف تأثیر بگذارد. فرایند سرویس به‌گونه‌ای مدیریت خواهد شد که گویی فرایند پس‌زمینه‌ای معمولی در فهرست LRU است، و این امر آن را برای ازبین بردن OOM واجدشرایط می‌کند، حتی زمانی‌که محدود شده باشد.
  • BIND_ABOVE_CLIENT: نشان می‌دهد که سرویس از خود برنامه کارخواه مهم‌تر است. وقتی سیستم نیاز به بازیابی حافظه دارد، توقف اجباری برنامه کارخواه را به توقف اجباری سرویس محدودکننده ترجیح می‌دهد. این روش از BIND_AUTO_CREATE «قوی‌تر» است زیرا لایه محافظتی اضافه‌ای برای سرویس فراهم می‌کند که هزینه آن را کارخواه می‌پردازد.
  • BIND_NOT_PERCEPTIBLE: اهمیت سرویس هدف را به زیر سطح PERCEPTIBLE کاهش می‌دهد و به سیستم اجازه می‌دهد حافظه آن را بازیابی کند تا برای فرایندهای مهم‌تر قابل‌درک برای کاربر فضا ایجاد شود.

عملی: مشاهده تأثیرات اتصال

از برنامه MemoryLab استفاده خواهیم کرد تا نشان دهیم چگونه اتصال از برنامه TOP بر وضعیت فرایند جداگانه‌ای تأثیر می‌گذارد.

۱. راه‌اندازی MemoryLab

فرمان زیر برنامه را راه‌اندازی می‌کند. پس‌از باز شدن برنامه، مطمئن شوید برنامه در پیش‌زمینه باقی می‌ماند (هنوز دکمه «صفحه اصلی» را فشار ندهید یا برنامه‌ها را عوض نکنید).

adb shell am start -n com.android.memorylab/.MainActivity

۲. شناسایی فرایندها

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

adb shell dumpsys activity processes com.android.memorylab

تکه‌کد خروجی نمونه:

  Process OOM control (154 total, non-act at 7, non-svc at 7):
    Proc #0: fg       T/A/TOP  LCMNFUATI  t: 0 13470:com.android.memorylab/u0a417 (top-activity)
        oom: max=1001 curRaw=0 setRaw=0 cur=0 set=0
        state: cur=TOP  set=TOP   lastRss=0.00 lastCachedRss=0.00

فرایند اصلی com.android.memorylab را در وضعیت TOP خواهید دید. فرایند :remote هنوز شروع نشده است.

۳. اتصال راه‌انداز

برای راه‌اندازی اتصال سرویس، یک پخش به برنامه ارسال کنید:

adb shell am broadcast -a com.android.memorylab.LEAK_BINDER

۴. مشاهده وضعیت ارتقایافته

وضعیت‌های فرایند را دوباره بررسی کنید:

adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"

تکه‌کد خروجی نمونه:

  Proc #  1: vis      F/ /BTOP ---NFUATI  t: 0 13560:com.android.memorylab:remote/u0a417 (service)
    com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
    oom: max=1001 curRaw=100 setRaw=100 cur=100 set=100
    state: cur=BTOP set=BTOP  lastRss=0.00 lastCachedRss=0.00

فرایند :remote اکنون درحال اجرا است و در وضعیت BTOP (Bound TOP) با oom_score_adj ۱۰۰ قرار دارد. این سرویس به‌طور قابل‌توجهی بیشتر از سرویس پس‌زمینه معمولی (که در 500 یا بالاتر قرار دارد) محافظت می‌شود. نماد <=Proc{...} نشان می‌دهد کدام فرایند مسئول این ارتقای اولویت است.

۵. ارسال به پس‌زمینه

دکمه HOME (صفحه اصلی) را روی دستگاه فشار دهید. دوباره ایالت‌ها را بررسی کنید:

adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"

تکه‌کد خروجی نمونه:

    Proc #  2: prev     b/ /LAST --------I  t: 0 13560:com.android.memorylab:remote/u0a417 (service)
        com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
        oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
        state: cur=LAST set=LAST  lastRss=0.00 lastCachedRss=0.00
    Proc #  1: prev     b/ /LAST --------I  t: 0 13470:com.android.memorylab/u0a417 (previous)
        oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
        state: cur=LAST set=LAST  lastRss=209MB lastCachedRss=0.00

اکنون هر دو فرایند به حالت اولویت پایین‌تر (PREV / oom_score_adj 700) منتقل شده‌اند، زیرا فرایند کارخواه دیگر TOP نیست. (توجه: LAST در تخلیه وضعیت به وضعیت داخلی LAST_ACTIVITY اشاره دارد که در خلاصه‌های سطح بالا به PREV نگاشت می‌شود).

درحال تجزیه‌وتحلیل با procstats

ابزار procstats نمای تاریخی این وضعیت‌ها را ارائه می‌دهد.

# View stats for MemoryLab over the last hour
adb shell dumpsys procstats --hours 1 com.android.memorylab

تکه‌کد خروجی نمونه:

  *   com.android.memorylab / u0a417 / v37:
      *   Prc com.android.memorylab / u0a417 / v37:
             TOTAL: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
               Top: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
      *   Prc com.android.memorylab:remote / u0a417 / v37:
             TOTAL: 0.19%
           Bnd Top: 0.19%

در اینجا، Bnd Top نشان‌دهنده درصد زمانی است که فرایند ازراه‌دور توسط برنامه‌ای در وضعیت TOP محدود شده است.

ضبط و تحلیل اتصالات با Perfetto

درحالی‌که dumpsys به شما یک عکس آنی می‌دهد، Perfetto به شما امکان می‌دهد دقیقاً لحظه وقوع اتصال و نحوه تغییر امتیاز OOM را به‌طور هم‌زمان ببینید.

۱. ضبط کردن ردیابی

از پیکربندی‌ای استفاده کنید که شامل linux.process_stats و دسته atrace am باشد:

adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/service_bindings.perfetto-trace <<EOF
buffers: { size_kb: 65536 }
data_sources: {
    config {
        name: "linux.process_stats"
        process_stats_config { proc_stats_poll_ms: 100 }
    }
}
data_sources: {
    config {
        name: "linux.ftrace"
        ftrace_config { ftrace_events: "am/am_proc_bound" }
    }
}
duration_ms: 15000
EOF

۲. پرس‌وجو درباره انتقال‌های امتیاز کمبود حافظه

بااستفاده از PerfettoSQL، می‌توانید ببینید که امتیاز OOM فرایند راه دور چگونه نسبت به فرایند واسط کاربر تغییر کرده است:

SELECT ts, p.name, value AS oom_score_adj
FROM counter c
JOIN process_counter_track t ON c.track_id = t.id
JOIN process p USING (upid)
WHERE p.name LIKE 'com.android.memorylab%'
  AND t.name = 'oom_score_adj'
ORDER BY ts;

۳. شناسایی رویدادهای اتصال

برای دیدن اینکه دقیقاً چه زمانی وابستگی اتصالی برقرار شده است و کدام فرایند آن را آغاز کرده است، از این پُرسمان استفاده کنید:

SELECT
    s.ts,
    p.name AS process_name,
    t.name AS thread_name,
    s.name AS slice_name
FROM slice s
JOIN thread_track tt ON s.track_id = tt.id
JOIN thread t USING (utid)
JOIN process p USING (upid)
WHERE s.name LIKE 'bindService:{com.android.memorylab%';

اتصال‌های سیستم به برنامه

خود سیستم Android اغلب به سرویس‌های موجود در برنامه‌های طرف سوم متصل می‌شود تا عملکرد اصلی را ارائه دهد. اغلب هدف این اتصال‌ها کاهش تأخیر است. با زنده نگه داشتن فرایند و در حافظه، سیستم از سربار پرهزینه «راه‌اندازی سرد» (بار کردن APK، مقداردهی اولیه زمان اجرا، و ایجاد شیء «برنامه») هنگام وقوع تعامل مهم کاربر جلوگیری می‌کند. اتصال‌های دیگری وجود دارد که از راه‌اندازی سرد مکرر برای برنامه‌هایی که باید جریان‌های رویدادهای پس‌زمینه را مدیریت کنند، جلوگیری می‌کند.

در اینجا چند نمونه واقعی آورده شده است که می‌توانید در دستگاهی معمولی مشاهده کنید:

VoiceInteractor

کاربران انتظار دارند که دستیار دیجیتال در سیستم‌عامل تلفنشان تعبیه شده باشد، بتوانند آن را فوراً با گفتن کلمه کلیدی یا اشاره ورودی سریع فراخوانی کنند، و تعامل با آن روان و یکپارچه باشد.

وقتی راه‌انداز دستیار اتفاق می‌افتد (مثل کلمه کلیدی «Ok Google» در تلفن‌های Google Pixel)، دستیار دیجیتال باید فوراً پاسخ دهد. برای اطمینان از این موضوع، system_server اتصال دائمی به سرویس تعامل صوتی را که کاربر انتخاب کرده است حفظ می‌کند.

نموداری که اتصال system_server به فرایند تعامل‌گر «برنامه Google» را نشان می‌دهد

اگر وضعیت‌های فرایند را بررسی کنید (مثلاً بااستفاده از dumpsys activity processes)، ممکن است فرایندی مثل com.google.android.googlequicksearchbox:interactor را در وضعیت BFGS (سرویس پیش‌زمینه‌ای مقید) ببینید که با قید شدن از system_server (UID 1000) فعال نگه داشته شده است.

NotificationListenerService

برای برخی‌از اتصال‌های سیستم به برنامه، هدف تأخیر نیست، بلکه جلوگیری از راه‌اندازی‌های سرد مکرر است. NotificationListenerService، سرویسی که هنگام پست شدن یا برداشته شدن اعلان‌های جدید، تماس‌هایی را از سیستم دریافت می‌کند، نمونه‌ای عالی است. یک کاربر معمولی تلفن هوشمند ممکن است صدها اعلان درطول روز دریافت کند. اگر سیستم از شنونده اعلان جدا شود، احتمالاً فرایند آن برنامه به حالت ذخیره‌شده در حافظه پنهان می‌رود و ممکن است توسط «بستن ناشی از کمبود حافظه» متوقف شود.

وقتی اعلان بعدی می‌رسد - احتمالاً چند ثانیه بعد - سیستم مجبور می‌شود فرایند برنامه را دوباره از ابتدا راه‌اندازی سرد کند تا فقط رویداد را تحویل دهد. این چرخه مداوم توقف و راه‌اندازی سرد، واحد پردازش مرکزی و باتری بسیار بیشتری نسبت به نگه داشتن فرایند به‌صورت محدود و فعال در پس‌زمینه مصرف می‌کند.

«صفحه ۱-» راه‌انداز (فید اخبار)

برنامه‌های «راه‌انداز» مدرن معمولاً عملکرد پیمایش اصلی (نمادهای صفحه اصلی و ابزاره‌ها) را با فید خبری که در یکی از صفحه‌های راه‌انداز دردسترس است و به‌طور یکپارچه با تجربه کاربری «راه‌انداز» ادغام شده است ترکیب می‌کنند. فید اخبار ممکن است توسط برنامه دیگری ارائه شود. برای مثال، در Google Pixel، «راه‌انداز» با فیدی که توسط برنامه Google ارائه می‌شود ادغام می‌شود.

وقتی در صفحه اصلی تند به چپ می‌کشید تا فید اخبار را مشاهده کنید، انتقال باید روان باشد. راه‌انداز این کار را با اتصال به میانای سرویس در برنامه‌ای که فید اخبار را ارائه می‌دهد انجام می‌دهد و این اتصال را تا زمانی که راه‌انداز فعال است حفظ می‌کند. این کار باعث می‌شود محتوای فید حتی زمانی که به آن نگاه نمی‌کنید، در حافظه آماده و پردازش‌شده باقی بماند.

نمونه‌های رایج دیگر

  • راه‌انداز (HOME_APP_ADJ): برنامه راه‌انداز (صفحه اصلی) جایگاه ویژه خود را در فهرست اولویت دارد. اگرچه همیشه به سرویسی محدود نیست، HOME_APP_ADJ (معمولاً ۶۰۰) به آن اختصاص داده می‌شود. سیستم ترجیح می‌دهد راه‌انداز را فعال نگه دارد، زیرا کاربر به‌طور مکرر به آن بازمی‌گردد. درواقع، سیستم ترجیح می‌دهد برنامه قبلاً استفاده‌شده (PREV_APP_ADJ = 700) را متوقف کند تا اینکه راه‌انداز را متوقف کند، زیرا متوقف کردن راه‌انداز باعث می‌شود تجربه کاربری هنگام خروج از هر برنامه‌ای کند شود، چون کاربر باید منتظر بماند تا راه‌انداز از ابتدا راه‌اندازی شود.
  • ویرایشگر روش ورودی (IME): وقتی درحال تایپ کردن هستید، سیستم به برنامه صفحه‌کلید انتخابی شما (مثلاً Gboard) متصل می‌شود. این کار فرایند صفحه‌کلید را در وضعیت ارتقایافته نگه می‌دارد، حتی اگر صفحه‌کلید موقتاً پنهان شده باشد. این کار باعث می‌شود وقتی روی فیلد نوشتاری دیگری تک‌ضرب می‌زنید، صفحه‌کلید بتواند فوراً دوباره ظاهر شود.
  • پرداخت با NFC: وقتی برای پرداخت با تلفنتان ضربه می‌زنید، سیستم به سرویس پرداخت با NFC (مثلاً «کیف پول Google») متصل می‌شود. این تراکنش‌ها اغلب الزامات بی‌درنگ سخت‌گیرانه‌ای ازسوی پایانه فروشنده دارند. اگر برنامه پرداخت مجبور به راه‌اندازی سرد شود، ممکن است تراکنش با اتمام مهلت مواجه شود و ناموفق باشد.

معاوضه‌ها و افت شدید عملکرد

درحالی‌که اتصال‌ها برای عملکرد و درستی ضروری هستند، اما برای سلامت حافظه سیستم هزینه دارند.

  • کاهش انعطاف‌پذیری: هر فرایند محدودشده فرایندی است که LMK نمی‌تواند به‌راحتی آن را ببندد. این کار «بالشتک» فرایندهای ذخیره‌شده در حافظه نهان را که سیستم می‌تواند برای آزاد کردن حافظه تحت فشار استفاده کند کاهش می‌دهد.
  • تشدید افت عملکرد: اگر فرایندهای زیادی محدود شده باشند، ممکن است سیستم تقریباً هیچ فرایند پس‌زمینه‌ای برای متوقف کردن نداشته باشد. وقتی فشار حافظه افزایش می‌یابد، سیستم بسیار سریع‌تر «از پرتگاه عملکرد سقوط می‌کند» زیرا مجبور می‌شود فرایندهای مهم‌تری را متوقف کند یا حافظه نهان صفحه را درهم بکوبد.

الگوهای ضد اتصال سرویس رایج

ازآنجایی‌که اتصال‌های سرویس مستقیماً oom_score_adj را ارتقا می‌دهند، اشتباهات جزئی در چرخه حیات در نحوه دریافت یا ساختاردهی اتصال‌ها می‌تواند مقادیر زیادی از حافظه را در حالت‌های ممتاز (BTOP، BFGS، یا PERC) برای ساعت‌ها پین کند. هنگام طراحی یا ممیزی خدمات محدودکننده، مراقب این الگوهای ضد رایج باشید.

unbindService() فراموش‌شده در کلاینت‌های با عمر طولانی

اتصال به سرویسی از یک Application تک‌قلو، یک مدیر پس‌زمینه، یا یک Activity که bindService() را در onStart() بدون یک unbindService() منطبق در onStop() فراخوانی می‌کند، باعث نشت ServiceConnection می‌شود.

تا زمانی که این اتصال فعال باشد، فرایند هدف اولویت ارتقایافته کارخواه را به ارث می‌برد. اگر کلاینت یک مؤلفه سیستم پایدار یا یک برنامه پیش‌زمینه باشد، فرایند خدمات محدودکننده به‌طور نامحدود در BFGS یا BTOP سنجاق‌شده باقی می‌ماند (نزدیک به ۱۰۰٪ در procstats نشان داده می‌شود)، که مانع از بازیابی حافظه توسط LMK می‌شود، حتی زمانی که سرویس کاملاً غیرفعال است.

راه‌حل: اتصال‌های محدوده را دقیقاً به چرخه حیات مؤلفه‌ای که به آن‌ها نیاز دارد محدود کنید، یا زمان استراحت غیرفعال بودن را پیاده‌سازی کنید که پس‌از دوره‌ای از عدم فعالیت، unbindService() را فراخوانی کند. از لغو اتصال و اتصال مجدد در هر فراخوانی RPC جداگانه اجتناب کنید، زیرا این کار باعث کوبش فرایند و سربار مکرر راه‌اندازی Binder می‌شود؛ درعوض، فوران‌های کاری را پشت یک زمان‌سنج بیکاری کوتاه (مثلاً ۵ تا ۳۰ ثانیه) ادغام کنید.

هم‌مکان کردن سرویس محدودشده با واسط کاربر با مصرف حافظه بالا

به‌طور پیش‌فرض، همه مؤلفه‌ها در APK در یک فرایند اجرا می‌شوند. اگر برنامه‌تان سرویس محدودکننده سبکی (مثل NotificationListenerService، ارائه‌دهنده ابزاره، یا سرویس افزونه‌ای که سیستم یا راه‌انداز به آن محدود می‌شود) را در همان فرایند Activity اصلی‌تان نشان دهد، کل فرایند وضعیت ارتقایافته سرویس را به‌ارث می‌برد (BFGS یا PERC، معمولاً oom_score_adj ۲۰۰ یا کمتر).

وقتی کاربر واسط کاربر برنامه‌تان را باز می‌کند، فرایند سلسله‌مراتب‌های نمای بزرگ، بیت‌مپ‌های کدگشایی‌شده، و میان‌گیرهای گرافیکی را اختصاص می‌دهد. وقتی کاربر از صفحه خارج می‌شود، فرایند به CACHED (oom_score_adj از ۹۰۰ یا بالاتر) کاهش نمی‌یابد زیرا اتصال سرویس فعال فرایند را در سطح بالا نگه می‌دارد. این امر باعث دو مشکل ترکیبی می‌شود:

  • بدون فشرده‌سازی حافظه پس‌زمینه: CachedAppOptimizer سیستم فقط فرایندها را پس‌از ورود به حالت CACHED فشرده می‌کند.
  • بدون کاهش حافظه LRU ذخیره‌شده در حافظه نهان یا بازیابی LMK: سیستم فراخوان‌های برگشتی کاهش پس‌زمینه مرتبط با فهرست LRU ذخیره‌شده در حافظه نهان را (TRIM_MEMORY_BACKGROUND و بالاتر) ارائه نمی‌دهد، درحالی‌که اتصال سرویس فرایند را در حالت ارتقایافته نگه می‌دارد. اگر برنامه‌تان صریحاً منابع UI را در TRIM_MEMORY_UI_HIDDEN یا Activity.onStop() آزاد نکند، تخصیص‌های UI اوج در RAM با امتیاز OOM ممتاز پین‌شده می‌مانند و LMK نمی‌تواند به‌راحتی آن‌ها را بازیابی کند.

راه‌حل: وقتی میانای کاربر دیگر قابل‌مشاهده نیست، بااستفاده از Activity.onStop()، ComponentCallbacks2.onTrimMemory(TRIM_MEMORY_UI_HIDDEN)، Application.ActivityLifecycleCallbacks، یا ProcessLifecycleOwner، حافظه‌های پنهان میانای کاربر، نقشه‌های بیتی رمزگشایی‌شده، و مراجع نما را به‌طور صریح تخلیه کنید. یا اینکه سرویس همیشه محدودشده را بااستفاده از مشخصه مانیفست android:process به فرایند سبک و جداگانه‌ای منتقل کنید تا سیستم بتواند فرایند واسط کاربر اصلی شما را به حالت CACHED منتقل کند تا حافظه آن را به‌طور مستقل فشرده یا بازیابی کند.

حذف پرچم‌های چشم‌پوشی از اولویت

فراخوانی bindService() با BIND_AUTO_CREATE به‌تنهایی اولویت زمان‌بندی و حافظه کامل تماس‌گیرنده را به سرویس هدف منتقل می‌کند. وقتی برنامه پیش‌زمینه‌ای فقط بااستفاده از BIND_AUTO_CREATE به سرویس تجزیه‌وتحلیل، ثبت، یا واکشی اولیه پس‌زمینه‌ای متصل می‌شود، به‌طور ناخواسته آن کارگر پس‌زمینه‌ای را به BTOP ارتقا می‌دهد.

راه‌حل: هنگام اتصال به سرویس‌های کمکی یا سرویس‌های با بهترین تلاش که به سطح محافظت یکسانی با میانای کاربری پیش‌زمینه نیاز ندارند، BIND_AUTO_CREATE را با BIND_WAIVE_PRIORITY، BIND_NOT_FOREGROUND، یا BIND_NOT_PERCEPTIBLE ترکیب کنید تا سیستم همچنان بتواند فرایند هدف را در فهرست LRU ذخیره‌شده در حافظه نهان مدیریت کند.


← محلی | ↑ بالا | سراسر سیستم →