شناسایی جانک های مرتبط با عصبانیت

Jitter رفتار تصادفی سیستم است که از اجرای کار محسوس جلوگیری می کند. این صفحه نحوه شناسایی و رسیدگی به مسائل مربوط به jank را شرح می دهد.

تاخیر زمانبندی رشته برنامه

تأخیر زمان‌بندی واضح‌ترین علامت جیتر است: فرآیندی که باید اجرا شود قابل اجرا است اما برای مدت زمان قابل توجهی اجرا نمی‌شود. اهمیت تأخیر بسته به زمینه متفاوت است. مثلا:

  • یک رشته کمکی تصادفی در یک برنامه احتمالاً می تواند چندین میلی ثانیه بدون مشکل به تعویق بیفتد.
  • رشته رابط کاربری یک برنامه ممکن است بتواند 1-2 میلی ثانیه لرزش را تحمل کند.
  • درایور kthread‌هایی که به‌عنوان SCHED_FIFO اجرا می‌شوند، اگر قبل از اجرا به مدت 500 ما قابل اجرا باشند، ممکن است مشکلاتی ایجاد کنند.

زمان‌های قابل اجرا را می‌توان در systrace با نوار آبی رنگ قبل از بخش در حال اجرا از یک رشته شناسایی کرد. یک زمان قابل اجرا همچنین می تواند با طول زمان بین رویداد sched_wakeup برای یک رشته و رویداد sched_switch که شروع اجرای نخ را نشان می دهد تعیین شود.

موضوعاتی که بیش از حد طولانی هستند

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

  1. از cpusets همانطور که در Thermal throttling توضیح داده شده است استفاده کنید.
  2. مقدار CONFIG_HZ را افزایش دهید.
    • از نظر تاریخی، این مقدار روی سکوهای بازو و arm64 روی 100 تنظیم شده است. با این حال، این یک تصادف تاریخی است و ارزش خوبی برای استفاده برای دستگاه های تعاملی نیست. CONFIG_HZ=100 به این معنی است که یک جیفی 10 میلی‌ثانیه طول دارد، به این معنی که تعادل بار بین CPUها ممکن است 20 میلی‌ثانیه (دو جیفی) طول بکشد. این می تواند به طور قابل توجهی به jank در یک سیستم بارگذاری شده کمک کند.
    • دستگاه‌های اخیر (Nexus 5X، Nexus 6P، Pixel، و Pixel XL) با CONFIG_HZ=300 ارسال شده‌اند. این باید هزینه انرژی ناچیزی داشته باشد و در عین حال زمان قابل اجرا را به طور قابل توجهی بهبود بخشد. اگر بعد از تغییر CONFIG_HZ افزایش قابل توجهی در مصرف انرژی یا مشکلات عملکرد مشاهده کردید، احتمالاً یکی از درایورهای شما از تایمر مبتنی بر جیفی های خام به جای میلی ثانیه استفاده می کند و به جیفی تبدیل می شود. این معمولاً یک راه حل آسان است ( وصله‌ای را ببینید که مشکلات تایمر kgsl را در Nexus 5X و 6P هنگام تبدیل به CONFIG_HZ=300 رفع کرد).
    • در نهایت، ما CONFIG_HZ=1000 را در Nexus/Pixel آزمایش کردیم و متوجه شدیم که به دلیل کاهش سربار RCU، عملکرد و توان قابل توجهی کاهش می‌دهد.

با این دو تغییر به تنهایی، یک دستگاه باید برای زمان اجرای رشته رابط کاربری تحت بار بسیار بهتر به نظر برسد.

با استفاده از sys.use_fifo_ui

می‌توانید با تنظیم ویژگی sys.use_fifo_ui روی 1، زمان اجرای رشته UI را به صفر برسانید.

هشدار : از این گزینه در پیکربندی‌های CPU ناهمگن استفاده نکنید، مگر اینکه یک زمان‌بندی RT آگاه از ظرفیت داشته باشید. و در حال حاضر، هیچ برنامه‌ریزی RT حمل‌ونقل در حال حاضر از ظرفیت آگاه نیست . ما در حال کار بر روی یکی برای EAS هستیم، اما هنوز در دسترس نیست. زمان‌بندی پیش‌فرض RT صرفاً بر اساس اولویت‌های RT است و اینکه آیا یک CPU قبلاً یک رشته RT با اولویت برابر یا بالاتر دارد.

در نتیجه، برنامه‌ریز RT پیش‌فرض با خوشحالی رشته رابط کاربری نسبتاً طولانی شما را از یک هسته بزرگ با فرکانس بالا به هسته‌ای کوچک با حداقل فرکانس منتقل می‌کند، اگر اتفاقاً یک FIFO kthread با اولویت بالاتر در همان هسته بزرگ بیدار شود. این رگرسیون عملکرد قابل توجهی را معرفی می کند . از آنجایی که این گزینه هنوز در یک دستگاه Android حمل‌ونقل استفاده نشده است، اگر می‌خواهید از آن استفاده کنید، با تیم عملکرد Android تماس بگیرید تا به شما در تأیید اعتبار آن کمک کند.

هنگامی که sys.use_fifo_ui فعال است، ActivityManager رشته رابط کاربری و RenderThread (دو رشته حیاتی UI) برنامه برتر را ردیابی می کند و آن رشته ها را به جای SCHED_OTHER SCHED_FIFO می کند. این به طور موثری لرزش را از UI و RenderThreads حذف می کند. ردیابی هایی که با فعال کردن این گزینه جمع آوری کرده ایم زمان های قابل اجرا را به جای میلی ثانیه به ترتیب میکروثانیه نشان می دهد.

با این حال، از آنجایی که متعادل کننده بار RT از ظرفیت آگاه نبود، 30 درصد کاهش در عملکرد راه اندازی برنامه وجود داشت زیرا رشته رابط کاربری مسئول راه اندازی برنامه از یک هسته طلایی Kryo با فرکانس 2.1 گیگاهرتز به یک هسته نقره ای Kryo با فرکانس 1.5 گیگاهرتز منتقل می شود. . با یک متعادل کننده بار RT آگاه از ظرفیت، عملکردی معادل در عملیات انبوه و کاهش 10 تا 15 درصدی در زمان های فریم صدک 95 و 99 در بسیاری از معیارهای رابط کاربری خود مشاهده می کنیم.

ترافیک را قطع کنید

از آنجایی که پلتفرم‌های ARM وقفه‌ها را فقط به‌صورت پیش‌فرض به CPU 0 ارائه می‌کنند، توصیه می‌کنیم از متعادل‌کننده IRQ (irqbalance یا msm_irqbalance در پلتفرم‌های Qualcomm) استفاده کنید.

در طول توسعه Pixel، ما jank را دیدیم که می‌توانست مستقیماً به CPU 0 با وقفه نسبت داده شود. برای مثال، اگر رشته mdss_fb0 روی CPU 0 برنامه ریزی شده بود، به دلیل وقفه ای که تقریباً بلافاصله قبل از اسکن توسط نمایشگر ایجاد می شود، احتمال jank بسیار بیشتر بود. mdss_fb0 در میانه کار خود با یک ضرب الاجل بسیار فشرده قرار می گیرد و سپس مدتی را به کنترل کننده وقفه MDSS از دست می دهد. در ابتدا، ما سعی کردیم این مشکل را با تنظیم وابستگی CPU رشته mdss_fb0 به CPUs 1-3 برای جلوگیری از مشاجره با وقفه برطرف کنیم، اما سپس متوجه شدیم که هنوز msm_irqbalance را فعال نکرده‌ایم. با فعال کردن msm_irqbalance، jank به میزان قابل توجهی بهبود یافت، حتی زمانی که هر دو وقفه mdss_fb0 و MDSS روی یک CPU بودند به دلیل کاهش اختلافات ناشی از وقفه‌های دیگر.

این را می توان در systrace با نگاه کردن به بخش sched و همچنین بخش irq شناسایی کرد. بخش sched آنچه را که برنامه ریزی شده است نشان می دهد، اما یک منطقه همپوشانی در بخش irq به این معنی است که به جای فرآیند برنامه ریزی شده معمول، یک وقفه در آن زمان در حال اجرا است. اگر مشاهده کردید که در طول یک وقفه زمان قابل توجهی صرف شده است، گزینه های شما عبارتند از:

  • کنترل کننده وقفه را سریعتر کنید.
  • از وقوع وقفه در وهله اول جلوگیری کنید.
  • فرکانس وقفه را تغییر دهید تا با سایر کارهای معمولی که ممکن است با آنها تداخل داشته باشد خارج از فاز باشد (اگر وقفه منظم باشد).
  • میل CPU وقفه را مستقیماً تنظیم کنید و از متعادل شدن آن جلوگیری کنید.
  • برای جلوگیری از وقفه، وابستگی CPU رشته ای را که وقفه با آن تداخل دارد تنظیم کنید.
  • برای انتقال وقفه به یک CPU با بارگذاری کمتر، به متعادل کننده وقفه تکیه کنید.

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

سافت ترک های بلند

در حالی که یک softirq در حال اجرا است، preemption را غیرفعال می کند. softirq ها همچنین می توانند در بسیاری از مکان های هسته فعال شوند و می توانند در داخل یک فرآیند کاربر اجرا شوند. اگر فعالیت softirq به اندازه کافی وجود داشته باشد، فرآیندهای کاربر اجرای softirq را متوقف می‌کنند و ksoftirqd برای اجرای softirq و بارگذاری متعادل می‌شود. معمولاً این خوب است. با این حال، یک نرم افزار بسیار طولانی می تواند سیستم را خراب کند.


softirq ها در بخش irq یک ردیابی قابل مشاهده هستند، بنابراین اگر مشکل در حین ردیابی قابل بازتولید باشد، به راحتی قابل تشخیص است. از آنجایی که یک softirq می‌تواند در یک فرآیند کاربر اجرا شود، یک softirq بد نیز می‌تواند به عنوان زمان اجرا اضافی در داخل یک فرآیند کاربر بدون دلیل واضح ظاهر شود. اگر متوجه شدید، بخش irq را بررسی کنید تا ببینید آیا softirqs مقصر هستند یا خیر.

رانندگانی که Preemption یا IRQ را برای مدت طولانی غیرفعال می کنند

غیرفعال کردن preemption یا وقفه‌ها برای بیش از حد طولانی (ده‌ها میلی‌ثانیه) منجر به jank می‌شود. به طور معمول، jank به صورت یک رشته قابل اجرا است اما روی یک CPU خاص اجرا نمی شود، حتی اگر موضوع قابل اجرا به طور قابل توجهی اولویت بالاتری (یا SCHED_FIFO) نسبت به رشته دیگر داشته باشد.

برخی از دستورالعمل ها:

  • اگر رشته قابل اجرا SCHED_FIFO باشد و رشته در حال اجرا SCHED_OTHER باشد، رشته در حال اجرا دارای Preemption یا وقفه غیرفعال است.
  • اگر thread قابل اجرا به طور قابل توجهی اولویت بالاتری (100) نسبت به رشته در حال اجرا (120) داشته باشد، در صورتی که رشته قابل اجرا در عرض دو جفی اجرا نشود، احتمالاً رشته در حال اجرا دارای preemption یا وقفه غیرفعال است.
  • اگر thread قابل اجرا و رشته در حال اجرا دارای اولویت یکسانی باشند، رشته در حال اجرا احتمالاً دارای preemption یا وقفه غیرفعال است اگر رشته قابل اجرا در 20 میلی ثانیه اجرا نشود.

به خاطر داشته باشید که اجرای یک کنترل کننده وقفه از سرویس دهی سایر وقفه ها جلوگیری می کند، که این امر پیش دستی را نیز غیرفعال می کند.


گزینه دیگری برای شناسایی مناطق متخلف با ردیاب preemptirqsoff است ( به استفاده از ftrace پویا مراجعه کنید). این ردیاب می تواند بینش بسیار بیشتری در مورد علت اصلی یک منطقه بدون وقفه (مانند نام توابع) ارائه دهد، اما برای فعال کردن به کار تهاجمی بیشتری نیاز دارد. در حالی که ممکن است تاثیر بیشتری بر عملکرد داشته باشد، قطعا ارزش امتحان کردن را دارد.

استفاده نادرست از صف های کاری

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

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

به جای یک صف کار، درایورهایی که نیاز به کار وقفه مانند در داخل یک رشته جداگانه دارند، باید SCHED_FIFO kthread خود را ایجاد کنند. برای کمک به انجام این کار با توابع kthread_work، به این پچ مراجعه کنید.

مناقشه قفل چارچوب

مناقشه قفل چارچوب می‌تواند منبعی از jank یا سایر مشکلات عملکرد باشد. معمولاً توسط قفل ActivityManagerService ایجاد می شود اما در قفل های دیگر نیز قابل مشاهده است. به عنوان مثال، قفل PowerManagerService می تواند روی عملکرد صفحه نمایش تأثیر بگذارد. اگر این مورد را در دستگاه خود مشاهده می کنید، راه حل خوبی وجود ندارد زیرا تنها از طریق بهبودهای معماری در چارچوب قابل بهبود است. با این حال، اگر کدی را که در داخل system_server اجرا می‌شود تغییر می‌دهید، بسیار مهم است که از نگه‌داشتن قفل‌ها برای مدت طولانی، به‌ویژه قفل ActivityManagerService اجتناب کنید.

جدال قفل کلاسور

از لحاظ تاریخی، کلاسور دارای یک قفل جهانی واحد بوده است. اگر رشته‌ای که یک تراکنش بایندر را انجام می‌دهد، در حالی که قفل را نگه می‌دارد، از قبل استفاده می‌شود، تا زمانی که رشته اصلی قفل را آزاد نکند، هیچ رشته دیگری نمی‌تواند تراکنش بایندر را انجام دهد. این بد است؛ جدال بایندر می‌تواند همه چیز را در سیستم مسدود کند، از جمله ارسال به‌روزرسانی‌های رابط کاربری به صفحه نمایش (رشته‌های رابط کاربری از طریق بایندر با SurfaceFlinger ارتباط برقرار می‌کنند).

Android 6.0 شامل چندین وصله برای بهبود این رفتار با غیرفعال کردن پیش‌پرداخت در حین نگه داشتن قفل کلاسور بود. این تنها به این دلیل امن بود که قفل بایندر باید برای چند میکروثانیه از زمان اجرای واقعی نگه داشته شود. این به طور چشمگیری عملکرد را در موقعیت‌های نامناسب بهبود می‌بخشد و با جلوگیری از اکثر سوئیچ‌های زمان‌بندی در حالی که قفل بایندر نگه داشته می‌شد، از مشاجره جلوگیری می‌کرد. با این حال، preemption را نمی‌توان برای کل زمان اجرای نگه‌داشتن قفل کلاسور غیرفعال کرد، به این معنی که preemption برای عملکردهایی که می‌توانستند بخوابند (مانند copy_from_user) فعال شده بود، که می‌تواند همان پیش‌پرداخت را ایجاد کند که مورد اصلی است. وقتی وصله‌ها را به بالادست فرستادیم، بلافاصله به ما گفتند که این بدترین ایده در تاریخ است. (ما با آنها موافق بودیم، اما همچنین نمی‌توانستیم با اثربخشی وصله‌ها در جلوگیری از jank بحث کنیم.)

اختلاف fd در یک فرآیند

این نادر است. جک شما احتمالا به این دلیل نیست.

گفته می‌شود، اگر چندین رشته در یک فرآیند دارید که همان fd را می‌نویسد، ممکن است در این fd مشاجره مشاهده شود، با این حال تنها زمانی که ما این موضوع را در هنگام نمایش پیکسل مشاهده کردیم، در طول آزمایشی بود که رشته‌های با اولویت پایین سعی کردند تمام CPU را اشغال کنند. زمانی که یک رشته با اولویت بالا در همان فرآیند در حال اجرا بود. همه رشته‌ها روی نشانگر ردیابی fd می‌نوشتند و رشته با اولویت بالا می‌تواند روی نشانگر ردیابی fd مسدود شود، اگر رشته‌ای با اولویت پایین قفل fd را نگه داشته باشد و سپس از آن استفاده شود. وقتی ردیابی از رشته‌های با اولویت پایین غیرفعال شد، مشکلی در عملکرد وجود نداشت.

ما نتوانستیم این را در هیچ موقعیت دیگری بازتولید کنیم، اما ارزش آن را دارد که به عنوان یک علت بالقوه مشکلات عملکرد هنگام ردیابی اشاره کنیم.

انتقال غیر ضروری CPU بیکار

هنگام برخورد با IPC، به ویژه خطوط لوله چند فرآیندی، مشاهده تغییرات در رفتار زمان اجرا زیر معمول است:

  1. Thread A روی CPU 1 اجرا می شود.
  2. موضوع A رشته B را بیدار می کند.
  3. Thread B روی CPU 2 شروع به اجرا می کند.
  4. رشته A بلافاصله به خواب می رود، تا زمانی که نخ B کار فعلی خود را به پایان رساند، توسط نخ B بیدار می شود.

یک منبع متداول سربار بین مراحل 2 و 3 است. اگر CPU 2 بیکار باشد، باید قبل از اجرای رشته B به حالت فعال برگردانده شود. بسته به SOC و عمق بیکار، این می تواند ده ها میکروثانیه قبل از شروع رشته B باشد. اگر زمان اجرای واقعی هر طرف IPC به اندازه کافی به سربار نزدیک باشد، عملکرد کلی آن خط لوله می تواند به میزان قابل توجهی با انتقال بیکار CPU کاهش یابد. متداول‌ترین مکان برای اندروید در مورد تراکنش‌های بایندر است و بسیاری از سرویس‌هایی که از بایندر استفاده می‌کنند، مانند وضعیتی که در بالا توضیح داده شد، ظاهر می‌شوند.

ابتدا از تابع wake_up_interruptible_sync() در درایورهای هسته خود استفاده کنید و از هر زمان‌بندی سفارشی پشتیبانی کنید. این را به عنوان یک نیاز، نه یک اشاره، در نظر بگیرید. Binder امروزه از این مورد استفاده می‌کند و به تراکنش‌های همزمان بایندر کمک می‌کند تا از انتقال‌های غیر ضروری CPU بی‌حرکت جلوگیری کند.

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

ورود به سیستم

ثبت‌نام برای چرخه‌های CPU یا حافظه رایگان نیست، بنابراین بافر گزارش را اسپم نکنید. چرخه هزینه های ثبت در برنامه شما (مستقیم) و در شبح ورود. قبل از ارسال دستگاه خود، هرگونه گزارش اشکال زدایی را حذف کنید.

مشکلات ورودی/خروجی

عملیات ورودی/خروجی منابع رایج جیتر هستند. اگر یک رشته به فایل نگاشت حافظه دسترسی پیدا کند و صفحه در کش صفحه نباشد، خطا می کند و صفحه را از دیسک می خواند. این موضوع را مسدود می کند (معمولاً برای 10+ ms) و اگر در مسیر بحرانی رندر UI اتفاق بیفتد، می تواند منجر به jank شود. دلایل زیادی برای عملیات ورودی/خروجی وجود دارد که در اینجا نمی‌توان به آن اشاره کرد، اما هنگام تلاش برای بهبود رفتار ورودی/خروجی، مکان‌های زیر را بررسی کنید:

  • PinnerService . PinnerService که در اندروید 7.0 اضافه شده است، چارچوب را قادر می سازد تا برخی از فایل ها را در کش صفحه قفل کند. این کار، حافظه را برای استفاده در هر فرآیند دیگری حذف می‌کند، اما اگر برخی از فایل‌ها وجود داشته باشند که قبلاً به طور منظم استفاده می‌شوند، می‌توان آن فایل‌ها را مسدود کرد.

    در دستگاه‌های Pixel و Nexus 6P دارای Android 7.0، چهار فایل را قفل کردیم:
    • /system/framework/arm64/boot-framework.oat
    • /system/framework/oat/arm64/services.odex
    • /system/framework/arm64/boot.oat
    • /system/framework/arm64/boot-core-libart.oat
    این فایل‌ها دائماً توسط اکثر برنامه‌ها و system_server استفاده می‌شوند، بنابراین نباید صفحه‌بندی شوند. به طور خاص، ما متوجه شده‌ایم که اگر هر یک از آن‌ها صفحه‌بندی شوند، مجدداً صفحه‌بندی می‌شوند و هنگام جابجایی از یک برنامه سنگین وزن باعث ایجاد jank می‌شوند.
  • رمزگذاری یکی دیگر از دلایل احتمالی مشکلات I/O. ما دریافتیم که رمزگذاری درون خطی بهترین عملکرد را در مقایسه با رمزگذاری مبتنی بر CPU یا استفاده از یک بلوک سخت افزاری قابل دسترسی از طریق DMA ارائه می دهد. مهمتر از همه، رمزگذاری درون خطی، لرزش مرتبط با I/O را کاهش می دهد، به خصوص زمانی که با رمزگذاری مبتنی بر CPU مقایسه می شود. از آنجایی که واکشی‌ها به کش صفحه اغلب در مسیر بحرانی رندر رابط کاربری قرار دارند، رمزگذاری مبتنی بر CPU بار اضافی CPU را در مسیر بحرانی وارد می‌کند که باعث ایجاد لرزش بیشتر از واکشی I/O می‌شود.

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

بسته بندی کار کوچک تهاجمی

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

حذف کش صفحه

یک دستگاه بدون حافظه آزاد کافی ممکن است در حین انجام یک عملیات طولانی مدت، مانند باز کردن یک برنامه جدید، ناگهان بسیار کند شود. ردی از برنامه ممکن است نشان دهد که در طول یک اجرای خاص به طور مداوم در I/O مسدود شده است، حتی زمانی که اغلب در I/O مسدود نشده است. این معمولاً نشانه‌ای از thrash شدن حافظه پنهان صفحه است، به خصوص در دستگاه‌هایی که حافظه کمتری دارند.

یکی از راه‌های شناسایی این است که یک systrace را با استفاده از تگ pagecache بگیرید و آن ردیابی را به اسکریپت در system/extras/pagecache/pagecache.py وارد کنید. pagecache.py درخواست‌های فردی را برای نگاشت فایل‌ها در حافظه پنهان صفحه به آمار کل فایل ترجمه می‌کند. اگر متوجه شدید که بایت های بیشتری از یک فایل از حجم کل آن فایل روی دیسک خوانده شده است، قطعاً در حال ضربه زدن به صفحه کش کش هستید.

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

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

  • از حافظه کمتری در فرآیندهای مداوم استفاده کنید. هرچه حافظه کمتری توسط فرآیندهای مداوم استفاده شود، حافظه بیشتری در دسترس برنامه ها و حافظه پنهان صفحه است.
  • حکاکی هایی را که برای دستگاه خود دارید بررسی کنید تا مطمئن شوید که بی جهت حافظه را از سیستم عامل حذف نمی کنید. ما موقعیت‌هایی را دیده‌ایم که حکاکی‌هایی که برای اشکال‌زدایی استفاده می‌شوند، به‌طور تصادفی در پیکربندی‌های هسته حمل و نقل رها شده‌اند و ده‌ها مگابایت حافظه مصرف می‌کنند. این می تواند تفاوت بین ضربه زدن به کش صفحه و عدم آن را ایجاد کند، به خصوص در دستگاه هایی با حافظه کمتر.
  • اگر در system_server در فایل‌های حیاتی، کش صفحه را می‌بینید، آن فایل‌ها را پین کنید. این باعث افزایش فشار حافظه در جاهای دیگر می شود، اما ممکن است رفتار را به اندازه کافی تغییر دهد تا از کوبیدن جلوگیری کند.
  • Lowmemorykiller را مجددا تنظیم کنید تا سعی کنید حافظه بیشتری را آزاد نگه دارید. آستانه‌های lowmemorykiller هم بر اساس حافظه آزاد مطلق و هم بر روی حافظه پنهان صفحه هستند، بنابراین افزایش آستانه‌ای که در آن پردازش‌ها در سطح oom_adj معین از بین می‌روند ممکن است منجر به رفتار بهتر در بهای افزایش مرگ برنامه پس‌زمینه شود.
  • سعی کنید از ZRAM استفاده کنید. ما از ZRAM در Pixel استفاده می‌کنیم، حتی اگر Pixel 4 گیگابایت دارد، زیرا می‌تواند به صفحات کثیف که به ندرت استفاده می‌شوند کمک کند.