Uygulamanızın kodundaki bir nesneyi serbest bırakmak veya geçici bir akışı kapatmak, fiziksel RAM'i her zaman işletim sistemine döndürmez. Özel yerel ayırıcılar, çöp toplayıcılı çalışma zamanları ve açık adresli karma tablolar, içlerindeki mantıksal veriler kaybolduktan uzun süre sonra fiziksel sayfalar tarafından desteklenmeye devam eden sanal bellek alanlarını sık sık korur. Benzer şekilde, büyük öğe arşivlerini okumak veya bellek eşlemek, uygulamanızın bellek kontrol grubuna (memcg) bağlı kalan çekirdek sayfa önbelleğini doldurur.
Bu sayfada, sanal adres rezervasyonlarını ve dosya tanımlayıcıları olduğu gibi korurken kullanılmayan anonim ve dosya destekli sayfaları işletim sistemine döndürmek için madvise ve posix_fadvise sistem çağrılarının nasıl kullanılacağı ve bu işlemin adb shell ile Perfetto üzerindeki etkisinin nasıl doğrulanacağı açıklanmaktadır.
Mantıksal ayırma kaldırma işlemi neden fiziksel RAM'i korur?
Linux çekirdeği, fiziksel belleği donanım sayfalarının ayrıntı düzeyinde izler. Bu sayfalar, Android cihazlarda 4 KB veya 16 KB'tır. Bir işlem, mmap ile sanal adres alanının bir bölgesini ayırdığında çekirdek, fiziksel RAM tahsis etmeden bir sanal bellek alanı (VMA) oluşturur. Çekirdek, fiziksel bir sayfayı yalnızca işlem o sayfaya ilk kez dokunduğunda tahsis eder ve ücretlendirir. Anonim bellek için ilk okuma, paylaşılan bir sıfır sayfasını eşler. Bu nedenle, yalnızca yazma işlemi RAM'i tahsis eder.
Bir sayfa RAM'e yüklendikten sonra çekirdek, bu sayfadaki baytların uygulamanızın çalışma zamanında hâlâ canlı nesneleri temsil edip etmediğini bilmez. Uygulamanız fiziksel sayfaları kullanmayı bıraktıktan sonra sayfaların yerleşik kalmasına neden olan iki yaygın model vardır:
- Anonim alanlar ve havuzlar: Özel yerel ayırıcılar (ör. slab, havuz veya çerçeve alanı ayırıcıları), taşınmayan yığın alanlarına sahip yönetilen çalışma zamanları ve büyük karma tablolar,
mmapkullanarakMAP_PRIVATE | MAP_ANONYMOUSile bitişik sanal adres aralıklarını ayırır. Uygulamanız bir arenayı sıfırladığında, bir bloğu özel bir havuza geri bıraktığında veya meta verilerini sıfırlayarak bir karma tabloyu temizlediğinde temel sayfalar kirli kalır. Çekirdeğe açık bir ipucu verilmediği sürece bu sayfalar, işleminizin anonim yerleşik küme boyutuna (RSS) ve orantılı küme boyutuna (PSS) vememory.currentcgroup ücretine dahil edilmeye devam eder. Bellek baskısı altında çekirdek, bunları ZRAM'e sıkıştırır ve buradamemory.swap.currentiçin ücretlendirilen takas alanını kaplamaya devam ederler. - Öğe akışından dosya destekli sayfa önbelleği: Uygulamanız
read,preadveya dosya desteklimmapkullanarak büyük öğe paketlerini, seviye arşivlerini, medya kapsayıcılarını ya da makine öğrenimi modellerini okuduğunda çekirdek, okunan her sayfayı sayfa önbelleğinde önbelleğe alır ve bu sayfaları işleminizin cgroup'ununmemory.statdosyasındakifilesayacına ekler. Uygulamanız bu öğeyi sıkıştırılmamış hale getiriyor veya anonim bir çalışma zamanı arabelleğine kopyalıyorsa ya da GPU'ya yüklüyorsa ham dosya sayfalarını sayfa önbelleğinde tutmak, öğeyi RAM'de kopyalar.
Anonim sayfaları yayınlama
madvise sistem çağrısı, çekirdeğe işleminizin sanal adres aralığını nasıl kullanmayı beklediği hakkında tavsiye verir. Özel anonim eşlemeler (MAP_PRIVATE |
MAP_ANONYMOUS) için MADV_DONTNEED parametresinin iletilmesi, çekirdeğe fiziksel sayfaları ve belirtilen sayfaya göre hizalanmış aralığı destekleyen tüm takas edilmiş ZRAM girişlerini hemen silmesini söyler.
madvise ile MADV_DONTNEED iadeden sonra:
- Sanal adres aralığı, işleminizin adres alanında ayrılmış ve geçerli kalır (
VmSizedeğişmez). Bu nedenle, işaretçiler ve alan sınırlarımunmapveyammapçağrılmadan olduğu gibi kalır. - Fiziksel sayfaların eşlemesi hemen kaldırılır ve serbest bırakılır. Böylece
RssAnon,Pss,memory.statiçindekianonsayacı ve ZRAM'deki tüm sayfalar içinmemory.swap.currentazaltılır. - Bu aralıktaki bir adrese yapılan sonraki okuma veya yazma işlemleri, isteğe bağlı olarak sıfırla doldurulmuş yeni bir sayfada hata verir.
| Tavsiye işareti | Hedef eşleme | Android'de çekirdek davranışı |
|---|---|---|
MADV_DONTNEED |
Gizli anonim (MAP_PRIVATE | MAP_ANONYMOUS) |
Fiziksel sayfaları ve ZRAM takas alanlarını hemen siler. Sonraki erişimlerde sıfırla doldurulmuş sayfalar hata verir. RssAnon ve memory.current için deterministik düşüş. |
MADV_DONTNEED |
Dosya destekli (MAP_PRIVATE veya MAP_SHARED) |
Sayfaların işlem sayfası tablolarıyla eşlemesini kaldırır (RssFile
bırakma). MAP_PRIVATE eşlemesindeki özel yazma sırasında kopyalama sayfaları silinir. Bu nedenle, değişiklikler kaybolur ve bir sonraki erişimde dosya yeniden okunur. Değiştirilmiş MAP_SHARED sayfalar daha sonra depolama alanına geri yazılır. Temiz sayfalar, çıkarılana kadar sayfa önbelleğinde kalır. |
MADV_FREE |
Gizli anonim (MAP_PRIVATE | MAP_ANONYMOUS) |
Sayfaları geç yeniden kullanılabilir olarak işaretler. Çekirdek, bellek baskısı yoksa RssAnon içindeki sayfaları korur ve yalnızca genel veya memcg geri alma işlemi çalıştırıldığında geri alır. |
MADV_WILLNEED |
Dosya destekli veya takas edilmiş anonim | Dosya destekli eşlemeler için eşzamansız önceden okumayı başlatır veya takas edilen anonim sayfaları ZRAM'den takas önbelleğine önceden okur. |
İç aralıkları çalışma zamanı sayfa boyutuna hizalama
madvise, tüm sayfalarda çalışır. Sayfaya göre hizalanmış bir başlangıç adresi gerektirir ve uzunluğu bir sonraki sayfa sınırına yuvarlar. Komşu baytların hâlâ canlı nesneler barındırdığı paylaşılan bir alanda bir aralığı serbest bırakırsanız aralığı dışa doğru yuvarlamak, sınır sayfalarını paylaşan canlı tahsisleri sıfırlayabilir.
Hem 4 KB hem de 16 KB sayfa boyutuna sahip cihazları desteklemek için çalışma zamanı sayfa boyutunu her zaman sysconf(_SC_PAGESIZE) ile sorgulayın ve iç başlangıç adresini bir sonraki sayfa sınırına, iç bitiş adresini ise önceki sayfa sınırına yuvarlayın. Sayfa boyutundan bağımsız ayırıcılar hakkında daha fazla bilgi için Özel bellek ayırıcıları optimize etme başlıklı makaleyi inceleyin.
#include <sys/mman.h>
#include <unistd.h>
#include <cstdint>
// Reclaims physical pages strictly inside [region_start, region_start + length)
// without disturbing live objects on partially occupied boundary pages.
void ReleaseUnusedArenaSpan(void* region_start, size_t length) {
const uintptr_t page_size = static_cast<uintptr_t>(sysconf(_SC_PAGESIZE));
const uintptr_t page_mask = ~(page_size - 1);
const uintptr_t raw_start = reinterpret_cast<uintptr_t>(region_start);
const uintptr_t raw_end = raw_start + length;
// Round start UP and end DOWN so only fully unused pages are discarded.
const uintptr_t aligned_start = (raw_start + page_size - 1) & page_mask;
const uintptr_t aligned_end = raw_end & page_mask;
if (aligned_end > aligned_start) {
madvise(reinterpret_cast<void*>(aligned_start),
aligned_end - aligned_start,
MADV_DONTNEED);
}
}
mmap ile özel anonim eşlemeler oluştururken PR_SET_VMA_ANON_NAME kullanarak VMA'yı prctl ile etiketleyin. Böylece, showmap ve /proc/<pid>/smaps içinde barındırma konumunu ada göre takip edebilirsiniz. dumpsys
meminfo, Unknown altındaki özel olarak adlandırılmış anonim bölgeleri sayar.
Bazı eski çekirdekler, adı kopyalamak yerine adın işaretçisini saklar. Bu nedenle, eşlemenin kullanım ömrü boyunca geçerli kalacak bir dize (ör. dize sabiti) iletin:
#include <sys/mman.h>
#include <sys/prctl.h>
#ifndef PR_SET_VMA
#define PR_SET_VMA 0x53564d41
#define PR_SET_VMA_ANON_NAME 0
#endif
void* ReserveNamedArena(size_t capacity_bytes, const char* arena_name) {
void* ptr = mmap(nullptr, capacity_bytes, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (ptr != MAP_FAILED) {
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME,
reinterpret_cast<unsigned long>(ptr), capacity_bytes,
reinterpret_cast<unsigned long>(arena_name));
}
return ptr;
}
Dosya önbelleği sayfalarını çıkarma
Uygulamanız bir dosya tanımlayıcıdan veri okuduğunda çekirdek, gelecekteki okuma işlemlerini öngörerek dosyanın sayfalarını sayfa önbelleğinde önbelleğe alır. Bu, küçük yapılandırma dosyalarına veya paylaşılan kitaplıklara tekrarlanan erişimleri hızlandırsa da büyük öğe arşivleri, doku paketleri veya bir kez ayrıştırılıp başka bir yerde kodu çözülmüş biçimde depolanan ses ve video parçaları akışla aktarılırken dezavantaj oluşturur.
posix_fadvise sistem çağrısı, uygulamanızın açık bir dosya tanımlayıcıda beklenen dosya erişim deseni hakkında çekirdeği bilgilendirmesini sağlar:
POSIX_FADV_DONTNEED: Çekirdeğe, belirtilen bayt aralığına yakın gelecekte erişilmeyeceğini bildirir. Çekirdek, bu sayfaya göre hizalanmış aralıktaki temiz, eşlenmemiş önbelleğe alınmış sayfaları sayfa önbelleğinden hemen çıkarır. Böylecememory.statiçindekifilesayacı ve cgroup'unuzunmemory.currentücreti azalır.POSIX_FADV_SEQUENTIAL: Dosya tanımlayıcı için çekirdeğin önceden okuma penceresini iki katına çıkararak büyük bir arşivin baştan sona akışında işleme hızını artırır. Sayfa önbelleği ayak izinin küçük bir kayan pencereyle sınırlı kalması için bunu, kullandığınız sırada sondaki parçalardaPOSIX_FADV_DONTNEEDile eşleştirin.POSIX_FADV_RANDOMDosya tanımlayıcıda tahmini çekirdek önceden okuma özelliğini devre dışı bırakır. Bu seçeneği, büyük bir arşiv veya veritabanı dosyasında bayt ofsetine göre seyrek, bitişik olmayan aramalar yaparken kullanın. Böylece her küçük okuma, bitişik kullanılmayan sayfaları sayfa önbelleğine çekmez. Bellekle eşlenen dosyalar için eşlemedeMADV_RANDOMilemadviseyöntemini çağırın.
Aşağıdaki örnekte, büyük bir öğe arşivi parçalar halinde aktarılır. Bu sayede, sıralı önceden okuma etkinleştirilir ve işlenen her sayfa hizalı aralık, sayfa önbelleğinden çıkarılır:
#include <fcntl.h>
#include <unistd.h>
#include <cstdint>
#include <vector>
void StreamAssetArchive(int fd, size_t total_size) {
const size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
constexpr size_t kChunkSize = 4 * 1024 * 1024; // 4 MB streaming window
std::vector<uint8_t> buffer(kChunkSize);
// Hint sequential access so the kernel prefetches upcoming chunks.
posix_fadvise(fd, 0, total_size, POSIX_FADV_SEQUENTIAL);
off_t offset = 0;
while (offset < static_cast<off_t>(total_size)) {
ssize_t bytes_read = pread(fd, buffer.data(), buffer.size(), offset);
if (bytes_read <= 0) break;
// Decode or upload buffer[0 .. bytes_read) into runtime structures here.
// Evict full pages that have been completely consumed.
const size_t aligned_len =
(static_cast<size_t>(bytes_read) / page_size) * page_size;
if (aligned_len > 0) {
posix_fadvise(fd, offset, static_cast<off_t>(aligned_len),
POSIX_FADV_DONTNEED);
}
offset += bytes_read;
}
}
Dosya destekli mmap bölgelerini geri alma
Uygulamanız büyük bir öğe dosyasını pread ile okumak yerine mmap ile belleğe eşliyorsa posix_fadvise işlevini yalnızca POSIX_FADV_DONTNEED ile çağırmak, işleminizin sayfa tablolarıyla eşlenmiş sayfaları kaldırmaz. Tüm VMA'nın eşlemesini kaldırmadan salt okunur bir dosya eşlemesinin tüketilen aralığını bırakmak için:
- Eşlenen sanal adres aralığında
madvise(addr, length, MADV_DONTNEED)işlevini çağırarak bu sayfaların işleminizin sayfa tablolarıyla eşlemesini kaldırın (RssFiledüşer). - İlgili dosya ofsetinde
posix_fadvise(fd, offset, length, POSIX_FADV_DONTNEED)işlevini çağırın. Böylece çekirdek, eşlenmemiş temiz sayfaları da sayfa önbelleğinden çıkarır (memory.statdüşüştefile).
Sayfa önerileriyle ilgili kurallara uyma
madvise ve posix_fadvise öğelerini ayırıcılara, öğe yükleyicilere ve yaşam döngüsü işleyicilere entegre ederken şu uygulamalardan yararlanın:
- Çağrıları kaba bölgelere toplu olarak işleme: Her
madviseçağrısı, işleminizin bellek haritası kilidini (mmap_lock) alır, sayfa tablolarını tarar ve diğer CPU çekirdeklerindeki eşleşen çeviri arama arabelleği (TLB) girişlerini geçersiz kılar (Arm'da yayın TLB bakım talimatları ve x86'da işlemciler arası kesintilerle). Her küçük ayırma kaldırma işlemindemadviseyöntemini çağırmayın. Boş alanları birleştirin ve çekirdeğe 64 KB ila 1 MB veya daha büyük parçalar halinde tavsiyede bulunun ya da kare sınırları ve arka plan geçişleri (onStopveTRIM_MEMORY_UI_HIDDEN) sırasında boş alanları tarayın. - Karma tablolarında ve havuzlarda boş kapasiteyi geri alma: Sahne geçişi veya veri senkronizasyonundan sonra büyük bir karma tablosu, nesne havuzu ya da hazırlama arabelleği temizlendiğinde, destekleyici tahsisini küçültün veya temizlenen destekleyici dizi genelinde
MADV_DONTNEEDyayınlayın. Mezar taşlarıyla ayrılmış 32 MB'lık açık adresli bir tablo tutmak, 32 MB'lık fiziksel sayfaların tamamının işleminizden ücretlendirilmesini sağlar. - Kirli dosya verilerini çıkarmadan önce temizleyin:
POSIX_FADV_DONTNEEDyalnızca temiz sayfa önbelleği sayfalarını çıkarır. Uygulamanız hemen geri okumayacağı büyük bir geçici dosya veya önbellek dosyası yazıyorsaposix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)işleminden öncefdatasyncyöntemini çağırın. Böylece kirli sayfalar depolama alanına yazılır ve ardından RAM'den silinir. - Sık kullanılan paylaşılan kodları veya öğeleri kaldırmayın: DEX, ODEX, VDEX, paylaşılan kitaplıklar (
.so) veya tekrar tekrar erişilen kullanıcı arayüzü öğelerindePOSIX_FADV_DONTNEEDişlevini çağırmaktan kaçının. Etkin kod veya öğe sayfalarının çıkarılması, iş parçacıklarını durduran ve G/Ç baskısını artıran eşzamanlı depolama hatalarına neden olur. Bu durum, baskı durma bilgileri (PSI) tarafından raporlanır.
Kabukta sayfa geri kazanımını doğrulama
showmap ve uygulamanızın cgroup v2 hesap dosyalarını kullanarak madvise ve posix_fadvise'nin fiziksel RAM'i geri aldığını doğrulayın.
Showmap ile sanal ve fiziksel boyutu inceleme
Anonim bir arenayı PR_SET_VMA_ANON_NAME ile adlandırdığınızda showmap, hem sanal rezervasyonunu (virtual size) hem de yerleşik fiziksel sayfalarını (RSS ve PSS) gösterir. Aşağıdaki örnek çıkış, arenasını memorylab-arena olarak adlandıran AOSP'deki MemoryLab örnek uygulamasından alınmıştır. com.example.app ve memorylab-arena ifadelerini paket adınız ve arena adınızla değiştirin. Dokunulan 64 MB'lık bir arenada MADV_DONTNEED ile madvise işlevini çağırmadan önce şunu çalıştırın:
adb shell "showmap \$(pidof com.example.app) | grep -E '^ +virtual|^ +size|memorylab-arena' | head -3"
virtual shared shared private private Anon Shmem File Shared Private
size RSS PSS clean dirty clean dirty swap swapPSS HugePages PmdMapped PmdMapped Hugetlb Hugetlb Locked # object
65536 65536 65536 0 0 0 65536 0 0 0 0 0 0 0 0 1 [anon:memorylab-arena]
madvise(arena_ptr, 64 * 1024 * 1024, MADV_DONTNEED) işlevini çağırdıktan sonra showmap işlevini tekrar çalıştırın:
virtual shared shared private private Anon Shmem File Shared Private
size RSS PSS clean dirty clean dirty swap swapPSS HugePages PmdMapped PmdMapped Hugetlb Hugetlb Locked # object
65536 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 [anon:memorylab-arena]
virtual size, 65.536 KB (64 MB) olarak kalır ve sanal adres aralığının hâlâ ayrılmış olduğunu onaylar. RSS, PSS ve private dirty ise 0 KB'a düşer.
cgroup memory.current ve memory.stat'ı inceleme
Hem anonim sayfa geri kazanımını hem de eşlenmemiş sayfa önbelleği tahliyesini (pread ile okunursa işlem sayfa tablolarında görünmez) doğrulamak için işlemin cgroup v2 dizinini inceleyin. Android'de her uygulama işleminin kendi cgroup'u vardır (cihaza bağlı olarak /sys/fs/cgroup/apps/uid_<UID>/pid_<PID>/ gibi).
Aşağıdaki komut, /proc/<PID>/cgroup dosyasının 0:: satırından dizini bulur ve sayaçları yazdırır:
adb shell '
PID=$(pidof com.example.app)
CG=/sys/fs/cgroup$(sed -n "s/^0:://p" /proc/$PID/cgroup)
echo "memory.current: $(cat $CG/memory.current)"
echo "memory.swap.current: $(cat $CG/memory.swap.current)"
grep -E "^(anon|file) " $CG/memory.stat
'
64 MB'lık anonim bir alanı serbest bırakmadan ve 128 MB'lık bellekle eşlenmiş bir öğe dosyasını sayfa önbelleğinden çıkarmadan önce:
memory.current: 242962432
memory.swap.current: 16633856
anon 100671488
file 140009472
Arena ve öğe dosyası eşlemesinde MADV_DONTNEED ile madvise işlevini, ardından öğe dosya tanımlayıcısında POSIX_FADV_DONTNEED ile posix_fadvise işlevini çağırdıktan hemen sonra:
memory.current: 41766912
memory.swap.current: 16502784
anon 33722368
file 5914624
anon 64 MB, file ise 128 MB düşer. Böylece dosya tanımlayıcı kapatılmadan veya alanın sanal adres alanının eşlemesi kaldırılmadan memory.current yaklaşık 192 MB azalır. memory.swap.current neredeyse hiç değişmez çünkü arena sayfalarının neredeyse hiçbiri ZRAM'e taşınmamıştır. Değerleriniz, cihaza ve çekirdeğin dosyanın ne kadarını kendi başına çıkardığına bağlıdır. Çekirdeğin cgroup başına belleği nasıl ücretlendirdiği ve geri aldığı hakkında daha fazla bilgi için Bellek geri alma: çıkarma ve takas bölümüne bakın.
Perfetto'da sayfa geri kazanımını analiz etme
Perfetto, madvise ve posix_fadvise çağrılarını birleştirilmiş bir zaman çizelgesinde çekirdek sayfa tablosu ve sayfa önbelleği sayaçlarıyla ilişkilendirmenize olanak tanır.
İz kaydetme
Periyodik işlem sayaçları için linux.process_stats ve anlık RSS ve sayfa önbelleği etkinlikleri için linux.ftrace ile bir izleme yakalayın, ardından bunu bilgisayarınıza çekin:
adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/page_advice.perfetto-trace <<EOF
buffers: {
size_kb: 65536
fill_policy: RING_BUFFER
}
data_sources: {
config {
name: "linux.process_stats"
process_stats_config {
scan_all_processes_on_start: true
proc_stats_poll_ms: 100
}
}
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "kmem/rss_stat"
ftrace_events: "filemap/mm_filemap_add_to_page_cache"
ftrace_events: "filemap/mm_filemap_delete_from_page_cache"
}
}
}
duration_ms: 20000
EOF
adb pull /data/misc/perfetto-traces/page_advice.perfetto-trace
Perfetto kullanıcı arayüzünde izleri inceleme
İzlemeyi Perfetto kullanıcı arayüzünde açın, uygulamanızın işlem grubunu genişletin ve aşağıdaki sayaç parçalarını sabitleyerek zaman çizelgesinin en üstünde kalmalarını sağlayın:
mem.virt:MADV_DONTNEEDçağrı boyunca sabit kalır ve sanal adres rezervasyonunun (mmap) değişmediğini doğrular.mem.rss.anon: Uygulamanızın kirli anonim arenalarda veya yığın bölgelerindeMADV_DONTNEEDilemadviseçağrısı yaptığı tam zaman damgasında keskin bir şekilde düşer.mem.rss.file: Uygulamanız, dosya destekli birmmapbölgesindeMADV_DONTNEEDilemadviseişlevini çağırdığında vePOSIX_FADV_DONTNEEDileposix_fadvise, temiz sayfaları sayfa önbelleğinden çıkardığında bir dizimm_filemap_delete_from_page_cacheftrace etkinliğiyle birlikte azalır.mem.swap:MADV_DONTNEED, daha önce ZRAM'e sıkıştırılmış anonim sayfaları sildiğinde düşer.
Şekil 2'de, MemoryLab örnek uygulaması için bu izler gösterilmektedir. Aynı görünümü incelemek için Perfetto kullanıcı arayüzünde örnek izi açın.
PerfettoSQL ile en yüksek ve nihai bellek kullanımını sorgulama
Hedef işleminiz için mem.virt, mem.rss.anon, mem.rss.file ve mem.swap değerlerinin en yüksek ve son değerlerini karşılaştırmak üzere Perfetto kullanıcı arayüzünde (Sorgu (SQL) sekmesi) aşağıdaki PerfettoSQL sorgusunu çalıştırın:
WITH counters AS (
SELECT t.name AS counter_name, c.ts, c.value
FROM counter c
JOIN process_counter_track t ON c.track_id = t.id
JOIN process p USING (upid)
WHERE p.name = 'com.example.app'
AND t.name IN ('mem.virt', 'mem.rss.anon', 'mem.rss.file', 'mem.swap')
)
SELECT
counter_name,
CAST(MAX(value) / 1048576 AS INT) AS peak_mb,
CAST((
SELECT value FROM counters AS last
WHERE last.counter_name = counters.counter_name
ORDER BY ts DESC LIMIT 1
) / 1048576 AS INT) AS final_mb
FROM counters
GROUP BY counter_name
ORDER BY counter_name;
Şekil 2'deki iz için örnek çıkış:
counter_name peak_mb final_mb
mem.rss.anon 111 48
mem.rss.file 212 84
mem.swap 36 36
mem.virt 13952 13952
mem.rss.anon, zirve noktasından 63 MB, mem.rss.file ise 128 MB düşerken mem.virt, sanal rezervasyonlar değişmediği için zirve noktasında biter.
Kaldırılan sayfaları dosyalara çözümleme
mm_filemap_add_to_page_cache ve mm_filemap_delete_from_page_cache etkinlikleri, dosyaları yol yerine inode numarasına (i_ino) göre tanımlar. Çıkarılan sayfaların önerdiğiniz dosyaya ait olduğunu doğrulamak için inode başına çıkarma sayısını hesaplayın:
SELECT
EXTRACT_ARG(arg_set_id, 'i_ino') AS inode,
COUNT(*) AS evicted_pages
FROM ftrace_event
WHERE name = 'mm_filemap_delete_from_page_cache'
GROUP BY inode
ORDER BY evicted_pages DESC
LIMIT 5;
Şekil 2'deki iz için örnek çıkış:
inode evicted_pages
9761 35781
76792192 767
126 668
0 612
11587712 514
İzi kaydeden cihaz hâlâ bağlıyken her inode'u bir yola çözümleyin. Inode numaraları yalnızca bir dosya sisteminde benzersizdir. Bu nedenle, aramayı uygulamanızın verilerini barındıran dosya sistemiyle sınırlayın:
INODE=<inode from the query>
adb shell "find /data -xdev -inum $INODE 2>/dev/null"
9761 inode'u için örnek çıkış:
/data/user/0/com.android.memorylab/files/asset_pack.bin
/data/data/com.android.memorylab/files/asset_pack.bin
/data/user/0 ve /data/data aynı uygulama verileri dizininin iki adı olduğundan her iki yol da aynı dosyayı ifade eder. Öğe dosyası için çıkarma sayısı (35.781 sayfa), dosyanın kendisinden (4 KB'ta 32.768 sayfa) daha büyük. Bunun nedeni,uygulama dosyayı tekrar okuyup posix_fadvise işlevini çağırmadan önce kswapd işlevinin, bellek baskısı altında dosyanın bir kısmını zaten çıkarmış olmasıdır.
Aynı anda birçok inode'u çözen bir komut dosyası için Önce inode'lardaki, ardından dosyalardaki hataları çözme bölümüne bakın.
← kswapd ve lmkd etkileşimi | ↑ Yukarı | Yalın arka plan işlemi →