Bellek sınırlayıcı

Android 17 ve sonraki sürümlerde, Linux cgroup v2'yi kullanarak uygulama işlemlerinin bellek kullanımını izleyen ve sınırlayan bir sistem hizmeti olan Bellek Sınırlayıcı bulunur. Bellek Sınırlayıcı, uygulamaların tek tek aşırı sistem belleği tüketmesini önler. Bu sayede genel bellek baskısı azalır ve kritik ön plan ve önbelleğe alınmış işlemlerin agresif bir şekilde sonlandırılması önlenir.

Sistem

Bellek Sınırlayıcı, işlem yaşam döngüsü etkinliklerini ve durum değişikliklerini izlemek için Etkinlik Yöneticisi Hizmeti (AMS) ile entegre olur. Bellek Sınırlayıcı, Linux çekirdeği cgroup v2 hiyerarşisini kullanarak bellek sınırlarını uygular.

Bellek Sınırlayıcı'yı desteklemek için cihaz çekirdeğinin cgroup v2'yi ve memory denetleyicisini etkinleştirmesi gerekir. Hizmet özellikle aşağıdaki özelliklere dayanır:

memory.high
Sanal sınır. Bu sınır aşıldığında işlem kısıtlanır ve çekirdek, bu işlemden proaktif sayfa geri alma işlemi yapmaya çalışır.
memory.swap.max
İşlemin kullanabileceği maksimum takas alanı miktarını (ör. ZRAM) sınırlar.

Uygulamalara etkisi

Bellek sınırları içinde çalışan uygulamalar, Bellek Sınırlayıcı'dan etkilenmez.

Bir uygulama memory.high sınırını aştığında çekirdek, uygulamanın temiz dosya destekli belleğini çıkarır ve etkin olmayan anonim belleğini değiştirerek uygulamayı sınır içinde tutar. Bu sayfa çıkarma ve takas etkinliği sonucunda uygulama geçici olarak yürütme kısıtlaması yaşayabilir ancak çalışmaya devam eder.

Uygulamanın, takas alanı tükendikten sonra anonim bellek ayırmaya devam ettiği kontrolsüz bellek sızıntısı gibi aşırı durumlarda uygulama, bellek ayıramaz ve sonlandırılır.

Süreç izleme

Bellek Sınırlayıcı, varsayılan olarak uygulama işlemlerini (UID >= 10000) izler. Temel sistem kararlılığını korumak için temel sistem işlemleri muaf tutulur.

Bellek Sınırlayıcı, bellek sınırlarını işlemin görünürlük durumuna göre atar:

  • Görünür işlemler: Kullanıcı tarafından görülebilen bir kullanıcı arayüzü barındıran işlemler (ör. şu anda odaklanılan etkinlik veya etkin bir etkileşim). Kullanıcı arayüzü görüntülemek, oluşturma ve grafik ardışık düzenleri için daha büyük bir çalışma kümesi gerektirdiğinden görünür işlemler daha geniş bir bellek sınırına sahiptir.

  • Görünür olmayan işlemler: Kullanıcı arayüzü sunmadan arka planda çalışan işlemler (ör. arka plan hizmetleri veya yayın alıcıları). Kullanıcı arayüzü bileşenlerini oluşturmadıkları için daha kısıtlayıcı bir sınır altında çalışırlar.

Aşağıdaki tabloda, belirli işlem durumları bellek sınırı sınıflandırmalarıyla eşlenmektedir:

İşlem durumuBellek sınırı
PERSISTENTKısıtlanmamış
PERSISTENT_UIKısıtlanmamış
TOPGörünür
BOUND_TOPGörünür
FOREGROUND_SERVICEGörünmez
BOUND_FOREGROUND_SERVICEGörünmez
IMPORTANT_FOREGROUNDGörünür
IMPORTANT_BACKGROUNDGörünmez
TRANSIENT_BACKGROUNDGörünmez
BACKUPGörünmez
SERVICEGörünmez
RECEIVERGörünmez
TOP_SLEEPINGGörünür
HEAVY_WEIGHTGörünmez
HOMEGörünmez
LAST_ACTIVITYGörünmez
CACHED_ACTIVITYÖnbelleğe alındı
CACHED_ACTIVITY_CLIENTÖnbelleğe alındı
CACHED_RECENTÖnbelleğe alındı
CACHED_EMPTYÖnbelleğe alındı

Önbelleğe alınmış durumda, işlemler dondurulur ve ardından maksimum düzeyde geri alınır.

Bir işlem, kendisine atanan memory.high sınırını aştığında Memory Limiter bu olayı algılar ve bellek profili yakalama veya statsd'e anormallik kaydetme gibi teşhis işlemlerini tetikleyebilir.

Yapılandırma

Android 17 ve sonraki sürümlerde Bellek Sınırlayıcı, /system/etc/memory-limiter-config.xml adresindeki sistem bölümünde bulunan standart platform yapılandırma dosyası kullanılarak yapılandırılır.

XML biçimi

Yapılandırma dosyası, memory-limiter-config.xsd içinde tanımlanan şemaya uyar. Dosya, kullanılabilir belleğe göre sıralanmış birden fazla sınır grubu tanımlar. Hizmet, cihazın kullanılabilir RAM'ine göre en yüksek eşleşen sınır grubunu seçer. Tüm bellek değerleri mebibayt (MiB) cinsinden belirtilir.

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <!-- RAM boundaries account for MemTotal excluding carve-outs. -->
    <limitSet>
      <!-- Limits for 16GB RAM device [14336, 18432): 10G/5G/5G/5G -->
      <minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>18432</maximumAllowedMemTotal>
      <memVisible>10240</memVisible>
      <memNotVisible>5120</memNotVisible>
      <swapVisible>5120</swapVisible>
      <swapNotVisible>5120</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 12GB RAM device [9216, 14336): 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>9216</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>14336</maximumAllowedMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 8GB RAM device [6800, 9216): 5G/3G/3G/3G -->
      <minimumRequiredMemTotal>6800</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>9216</maximumAllowedMemTotal>
      <memVisible>5120</memVisible>
      <memNotVisible>3072</memNotVisible>
      <swapVisible>3072</swapVisible>
      <swapNotVisible>3072</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 6GB RAM device [4800, 6800): 4G/2G/2G/2G -->
      <minimumRequiredMemTotal>4800</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>6800</maximumAllowedMemTotal>
      <memVisible>4096</memVisible>
      <memNotVisible>2048</memNotVisible>
      <swapVisible>2048</swapVisible>
      <swapNotVisible>2048</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 4GB RAM device [3200, 4800): 2G/1G/1G/1G -->
      <minimumRequiredMemTotal>3200</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>4800</maximumAllowedMemTotal>
      <memVisible>2048</memVisible>
      <memNotVisible>1024</memNotVisible>
      <swapVisible>1024</swapVisible>
      <swapNotVisible>1024</swapNotVisible>
    </limitSet>
  </configList>
</MemoryLimiterConfig>
version
Yapılandırma sürümünü tanımlayan pozitif bir tam sayı. Bu değer 1 olmalıdır.
minimumRequiredMemTotal

Bu sınır grubunun uygulanması için gereken minimum sistem MemTotal (MiB cinsinden, alt sınır dahil). Hizmet, bunu /proc/meminfo içinde çekirdek tarafından bildirilen toplam kullanılabilir belleğe göre değerlendirir.

Bellek ayırmalarını ve sınırlarını anlama: Çekirdek MemTotal değeri, donanım ve donanım yazılımı bellek ayırmaları düşüldükten sonra işletim sisteminin erişebileceği fiziksel DRAM'i yansıtır. Ayrılmış alanlar; GPU, temel bant modem, kamera ISP'si, güvenli yürütme ortamları ve hipervizörler gibi özel donanım bileşenleri için RAM ayırır. Bu bileşenler genellikle 500 MiB ile 2 GiB'ın üzerinde fiziksel bellek tüketir.

MemTotal, cihazın reklamı yapılan fiziksel DRAM'inden daha düşük olduğundan minimumRequiredMemTotal eşikleri bu ayırmalar için bir pay içerir. Örneğin, 16 GB'lık cihazları hedefleyen bir yapılandırma, 16384 (16 GiB) yerine 14336 (14 GiB) alt sınırını belirtir. 12 GB'lık cihazlar için bir katman ise 9216 (9 GiB) alt sınırını belirtir. Bu sayede, her cihazın, anakart düzeyindeki istisna varyasyonlarından bağımsız olarak amaçlanan katmanıyla eşleşmesi sağlanır.

maximumAllowedMemTotal

Bu sınırın uygulanması için maksimum sistem MemTotal (MiB cinsinden, özel tavan). MemTotal bu üst sınırdan büyük veya bu sınıra eşitse belirlenen sınır geçerli olmaz. 18.432 MiB veya daha fazla ya da 3.200 MiB'den az belleğe sahip cihazlarda Bellek Sınırlayıcı, sınır uygulamaz ve işlemleri kısıtlamaz.

memVisible

Görünür işlemlere uygulanan MiB cinsinden esnek bellek sınırı (memory.high).

memNotVisible

Görünür olmayan işlemlere uygulanan MiB cinsinden esnek bellek sınırı (memory.high).

swapVisible

Görünür işlemlere uygulanan MiB cinsinden takas alanı sınırı (memory.swap.max).

swapNotVisible

Görünür olmayan işlemlere uygulanan MiB cinsinden takas alanı sınırı (memory.swap.max).

Standart platform sınırları

Android 17 ve sonraki sürümlerde platform, [floor, ceiling) aralıklarını kullanarak yaygın fiziksel RAM katmanlarında /system/etc/memory-limiter-config.xml cinsinden standart bellek ve takas sınırlarını belirtir:

Hedef fiziksel RAM MemTotal aralığı [alt sınır, üst sınır)
(minimumRequiredMemTotal,
maximumAllowedMemTotal)
Görünür bellek sınırı
(memVisible)
Görünür olmayan bellek sınırı
(memNotVisible)
Görünür takas sınırı
(swapVisible)
Görünür olmayan takas sınırı
(swapNotVisible)
16 GB [14336, 18432) MiB 10.240 MiB (10 GiB) 5.120 MiB (5 GiB) 5.120 MiB (5 GiB) 5.120 MiB (5 GiB)
12 GB [9216, 14336) MiB 8.192 MiB (8 GiB) 4.096 MiB (4 GiB) 4.096 MiB (4 GiB) 4.096 MiB (4 GiB)
8 GB [6800, 9216) MiB 5.120 MiB (5 GiB) 3.072 MiB (3 GiB) 3.072 MiB (3 GiB) 3.072 MiB (3 GiB)
6 GB [4800, 6800) MiB 4.096 MiB (4 GiB) 2.048 MiB (2 GiB) 2.048 MiB (2 GiB) 2.048 MiB (2 GiB)
4 GB [3200, 4800) MiB 2.048 MiB (2 GiB) 1.024 MiB (1 GiB) 1.024 MiB (1 GiB) 1.024 MiB (1 GiB)

Bellek sınırı ilkeleri

Bellek Sınırlayıcı yapılandırması, aşağıdaki platform ilkelerine göre tasarlanmıştır:

  • Ekosistem tutarlılığı ve uygulama uyumluluğu: Cihazlar genelinde tutarlı bellek sınırları, Android ekosisteminde öngörülebilir uygulama performansı sağlar. Uygulamalar, standart bellek beklentilerine göre geliştirilir ve test edilir. Platform sınırlarının her yerde aynı olması, beklenmedik kısıtlamaları veya erken sonlandırmaları önler.

  • Orantılı kaynak tahsisi: Platform sınırları, fiziksel RAM kapasitesine göre ayarlanır:

    • Görünür işlemler: Etkin kullanıcı arayüzü, oluşturma ve oluşturma iş yüklerini desteklemek için toplam fiziksel RAM'in yaklaşık 1/2 ila 2/3'ü ayrılır.
    • Görünür olmayan işlemler: Arka plan görevleri için toplam fiziksel RAM'in yaklaşık 1/4 ila 1/3'ü ayrılır.
  • Evrensel uygulanabilirlik: Sınırlar, önceden yüklenmiş sistem ve OEM uygulamaları da dahil olmak üzere cihazdaki tüm uygulama işlemlerine (UID >= 10000) eşit şekilde uygulanır. Bellek Sınırlayıcı, belirli uygulamaları muaf tutmak için izin verilenler listelerini desteklemez. Bu sayede tüm uygulamalarda adil bellek yönetimi sağlanır. Kritik etkileşimli arka plan programlarında kendi kendine ayarlanan memory.min koruma tabanlarını ve ayrı sistem uygulamaları ile hizmetlerinde daha sıkı, iş yüküne göre ayarlanmış memory.high tavanlarını yapılandırmak için Sistem belleği bütçeleri başlıklı makaleyi inceleyin.

  • Çalışma zamanı sorgu API'lerinin olmaması: Android 17 ve sonraki sürümlerde uygulamalar, çalışma zamanında atanan bellek sınırlarını programatik olarak sorgulayamaz. Standart platform sınırları, iyi davranış sergileyen uygulamaların normal kullanım sırasında kısıtlama olmadan çalışması için geniş bir payla tanımlanır.

  • Çekirdek geri kazanımı ve takas dinamikleri: Bir uygulama işlemi memory.high sınırına yaklaştığında Linux çekirdeği, bellek geri kazanımını özellikle bu işlem cgroup'una yönlendirir. Bu kapsamda, etkin olmayan dosya destekli sayfalar bırakılır ve soğuk anonim sayfalar ZRAM'e taşınır. Böylece, genel bellek baskısı oluşturmadan sistem akıcılığı korunur.

Kabuk komutları

am memory-limiter komutu, geliştiricilerin ve sistem entegratörlerinin geliştirme, test ve hata ayıklama için çalışma zamanında hizmetle etkileşim kurmasına olanak tanır:

am memory-limiter <SUB-COMMAND>

durum

status alt komutu, bellek sınırlayıcının faaliyet durumunu ve etkin metriklerini bildirir:

adb shell am memory-limiter status

Aşağıda örnek bir çıkış verilmiştir:

Memory limiter
  enabled                  monitoring=true          ignored=none
  visibleMem=1948MB        visibleSwap=974MB
  notVisibleMem=974MB      notVisibleSwap=487MB
  started=36               watched=36               watch-failed=0
  events=0                 processes=36             process-hwm=36

Çıkıştaki önemli alanlar şunlardır:

monitoring
Bellek Sınırlayıcı'nın işlemleri etkin bir şekilde izleyip izlemediğini gösterir.
visibleMem ve notVisibleMem
Şu anda her görünürlük durumu için uygulanan hesaplanmış mutlak bellek sınırları (memory.high).
visibleSwap ve notVisibleSwap
Şu anda her görünürlük durumu için uygulanan, hesaplanmış mutlak takas sınırları (memory.swap.max).
events
Bir işlemin, kendisine atanan sınırı aşma sayısı.
processes
İzlenen işlemlerin mevcut sayısı.

yoksay

ignore alt komutu, belirli bir UID'yi veya tüm işlemleri geçici olarak bellek sınırlamasından hariç tutar. Bu, performans karşılaştırması, stres testi veya bellek davranışını teşhis etmek için kullanışlıdır:

# Ignore a specific UID
adb shell am memory-limiter ignore 10087
# Ignore all processes (temporarily disables limiting)
adb shell am memory-limiter ignore all
# Resume normal limiting operation
adb shell am memory-limiter ignore none

manuel

manual alt komutu, belirli bir işlem için hesaplanan sınırları işlem kimliğine (PID) göre bayt cinsinden özel bir mutlak değerle geçersiz kılar. Değer bir tam sayı olmalıdır ancak MiB'yi belirtmek için MB son ekini veya GiB'yi belirtmek için GB son ekini içerebilir:

# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1073741824
# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1024MB
# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1GB
# Remove the manual override for PID 1234
adb shell am memory-limiter manual 1234 none

Manuel geçersiz kılma işlemleri yalnızca ilgili işlem örneğinin kullanım ömrü boyunca geçerlidir. İşlem yeniden başlatılırsa durumuna göre standart sınırlara döner.

Manuel geçersiz kılma, fiziksel sistem sınırlarını aşamaz.