Linux bellek yönetiminde RSS ve VSZ nedir


Yanıtlar:


499

RSS Yerleşik Ayar Boyutudur ve bu işleme ne kadar bellek tahsis edildiğini ve RAM'de olduğunu göstermek için kullanılır. Değiştirilen belleği içermez. Bu kitaplıklardan gelen sayfalar gerçekte bellekte olduğu sürece, paylaşılan kitaplıklardan bellek içerir. Tüm yığın ve yığın belleği içerir.

VSZ, Sanal Bellek Boyutudur. Değiştirilen bellek, ayrılan ancak kullanılmayan bellek ve paylaşılan kitaplıklardan alınan bellek de dahil olmak üzere, işlemin erişebileceği tüm belleği içerir.

Yani A süreci 500K'lık bir ikili dosyaya sahipse ve 2500K paylaşılan kütüphaneye bağlıysa, 100K'sı gerçekte bellekte olan (geri kalanı değiştirilir veya kullanılmaz) 200K yığın / yığın tahsisine sahipse ve sadece 1000K paylaşılan kütüphaneleri yükledi ve kendi ikilisinin 400K'sı:

RSS: 400K + 1000K + 100K = 1500K
VSZ: 500K + 2500K + 200K = 3200K

Belleğin bir kısmı paylaşıldığından, birçok işlem bunu kullanabilir, bu nedenle tüm RSS değerlerini toplarsanız, sisteminizde olduğundan daha fazla alan elde edebilirsiniz.

Ayrılan bellek, aslında program tarafından kullanılıncaya kadar RSS'de olmayabilir. Dolayısıyla, programınız bir sürü bellek ayırdıysa, zamanla kullanırsa, RSS'nin yükseldiğini ve VSZ'nin aynı kaldığını görebilirsiniz.

Ayrıca PSS (orantılı set boyutu) vardır. Bu, paylaşılan belleği geçerli işlem tarafından kullanılan bir oran olarak izleyen daha yeni bir ölçüdür. Dolayısıyla, önceden aynı paylaşılan kitaplığı kullanan iki işlem varsa:

PSS: 400K + (1000K/2) + 100K = 400K + 500K + 100K = 1000K

İş parçacıklarının tümü aynı adres alanını paylaşır, böylece her iş parçacığı için RSS, VSZ ve PSS, işlemdeki diğer iş parçacıklarının tümü ile aynıdır. Bu bilgiyi linux / unix biçiminde görüntülemek için ps veya top komutunu kullanın.

Bundan daha fazla yol var, daha fazla bilgi edinmek için aşağıdaki referansları kontrol edin:

Ayrıca bakınız:


17
Ben RSS inanıyoruz yapar dinamik bağlantılı kütüphanelerden bellek yer alıyor. Kullanan 3 işlem varsa libxml2.so, paylaşılan kütüphane RSS'lerinin her birinde sayılır, bu nedenle RSS'lerinin toplamı kullanılan gerçek bellekten daha fazla olacaktır.
nfm

1
Bu doğru. Cevabımı düzelttim.
jmh

Ben ubuntu 16.04 üzerinde ve bir java işlemi 1.2G RES ve 4.5G VIRT komutundan gösteren vardır top. Bu sistemin herhangi bir takası yoktur, swapon --showhiçbir şey döndürmez. Bunu nasıl açıklıyorsunuz? Vsz takas + paylaşılan kütüphaneler ise, bu durumda, paylaşılan kütüphaneler 3.3G? Mümkün mü? Gerçekten şaşkın ...
Aaron Wang

Gerçekten emin değilim. Java sanal bellek kullanımı hakkındaki şu cevaba bir göz atın: stackoverflow.com/a/561450/622115 . Kısa sürüm: VSZ, ayrılmış ve kullanılmayan yığın alanı ve bellek eşlemeli dosyaları içerebilir.
jmh

Harika. Sadece bir şeyler ekleyin. Eğer malloc (100KB), o zaman sadece 1KB kullanın. Burada takas olmasa da rss 1K ve vsz 100K'dır.
keniee van

53

RSS Yerleşik Set Boyutu (fiziksel olarak yerleşik bellek - şu anda makinenin fiziksel belleğinde yer kaplıyor) ve VSZ Sanal Bellek Boyutu (ayrılmış adres alanı - bu işlemin bellek haritasında ayrılmış adresler var, ancak mutlaka gerçek bellek şimdi arkasında).

Günümüzde sıradan sanal makinelerde, makinenin bakış açısından fiziksel belleğin gerçek fiziksel bellek olmayabileceğini unutmayın.


Kısaltmanın ne anlama geldiğinden daha fazla bilgi sağlamak ister misiniz?
Pithikos

10

Minimal çalıştırılabilir örnek

Bunun mantıklı olması için, sayfalamanın temellerini anlamalısınız: x86 sayfalama nasıl çalışır? ve özellikle işletim sisteminin sanal belleği, RAM veya disk üzerinde bir yedek depolama alanına (RSS yerleşik belleği) sahip olmadan önce sayfa tabloları / dahili bellek defteri tutma (VSZ sanal bellek) aracılığıyla ayırabilir.

Şimdi bunu gözlemlemek için, aşağıdakileri yapan bir program oluşturalım:

  • fiziksel belleğimizden daha fazla RAM ayırır mmap
  • bu sayfaların her birinin yalnızca sanal bellekten (VSZ) gerçekte kullanılan belleğe (RSS) gitmesini sağlamak için her sayfada bir bayt yazar
  • işlemin bellek kullanımını aşağıdaki yöntemlerden biriyle kontrol eder: C'deki geçerli işlemin bellek kullanımı

main.c

#define _GNU_SOURCE
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

typedef struct {
    unsigned long size,resident,share,text,lib,data,dt;
} ProcStatm;

/* /programming/1558402/memory-usage-of-current-process-in-c/7212248#7212248 */
void ProcStat_init(ProcStatm *result) {
    const char* statm_path = "/proc/self/statm";
    FILE *f = fopen(statm_path, "r");
    if(!f) {
        perror(statm_path);
        abort();
    }
    if(7 != fscanf(
        f,
        "%lu %lu %lu %lu %lu %lu %lu",
        &(result->size),
        &(result->resident),
        &(result->share),
        &(result->text),
        &(result->lib),
        &(result->data),
        &(result->dt)
    )) {
        perror(statm_path);
        abort();
    }
    fclose(f);
}

int main(int argc, char **argv) {
    ProcStatm proc_statm;
    char *base, *p;
    char system_cmd[1024];
    long page_size;
    size_t i, nbytes, print_interval, bytes_since_last_print;
    int snprintf_return;

    /* Decide how many ints to allocate. */
    if (argc < 2) {
        nbytes = 0x10000;
    } else {
        nbytes = strtoull(argv[1], NULL, 0);
    }
    if (argc < 3) {
        print_interval = 0x1000;
    } else {
        print_interval = strtoull(argv[2], NULL, 0);
    }
    page_size = sysconf(_SC_PAGESIZE);

    /* Allocate the memory. */
    base = mmap(
        NULL,
        nbytes,
        PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS,
        -1,
        0
    );
    if (base == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    /* Write to all the allocated pages. */
    i = 0;
    p = base;
    bytes_since_last_print = 0;
    /* Produce the ps command that lists only our VSZ and RSS. */
    snprintf_return = snprintf(
        system_cmd,
        sizeof(system_cmd),
        "ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == \"%ju\") print}'",
        (uintmax_t)getpid()
    );
    assert(snprintf_return >= 0);
    assert((size_t)snprintf_return < sizeof(system_cmd));
    bytes_since_last_print = print_interval;
    do {
        /* Modify a byte in the page. */
        *p = i;
        p += page_size;
        bytes_since_last_print += page_size;
        /* Print process memory usage every print_interval bytes.
         * We count memory using a few techniques from:
         * /programming/1558402/memory-usage-of-current-process-in-c */
        if (bytes_since_last_print > print_interval) {
            bytes_since_last_print -= print_interval;
            printf("extra_memory_committed %lu KiB\n", (i * page_size) / 1024);
            ProcStat_init(&proc_statm);
            /* Check /proc/self/statm */
            printf(
                "/proc/self/statm size resident %lu %lu KiB\n",
                (proc_statm.size * page_size) / 1024,
                (proc_statm.resident * page_size) / 1024
            );
            /* Check ps. */
            puts(system_cmd);
            system(system_cmd);
            puts("");
        }
        i++;
    } while (p < base + nbytes);

    /* Cleanup. */
    munmap(base, nbytes);
    return EXIT_SUCCESS;
}

GitHub akış yukarı .

Derleyin ve çalıştırın:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
echo 1 | sudo tee /proc/sys/vm/overcommit_memory
sudo dmesg -c
./main.out 0x1000000000 0x200000000
echo $?
sudo dmesg

nerede:

  • 0x1000000000 == 64GiB: Bilgisayarımın 32GiB'lik fiziksel RAM'i
  • 0x200000000 == 8GiB: belleği her 8GiB'de yazdırın, böylece çökmeden önce 32GiB'de 4 baskı almalıyız
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory: Linux'un fiziksel RAM'den daha büyük bir mmap çağrısı yapmamıza izin vermesi için gereklidir: malloc'un ayırabileceği maksimum bellek

Program çıktısı:

extra_memory_committed 0 KiB
/proc/self/statm size resident 67111332 768 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 1648

extra_memory_committed 8388608 KiB
/proc/self/statm size resident 67111332 8390244 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 8390256

extra_memory_committed 16777216 KiB
/proc/self/statm size resident 67111332 16778852 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 16778864

extra_memory_committed 25165824 KiB
/proc/self/statm size resident 67111332 25167460 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 25167472

Killed

Çıkış durumu:

137

tarafından hangi 128 + sinyal numarası kuralı vasıtasıyla biz sinyal numarası var 9, man 7 signaldiyor sigkill Linux tarafından gönderilen, dışı belleğe katil .

Çıktı yorumu:

  • VSZ sanal belleği mmap'den sonra sabit kalır printf '0x%X\n' 0x40009A4 KiB ~= 64GiB( psdeğerler KiB cinsindendir).
  • RSS "gerçek bellek kullanımı" yalnızca sayfalara dokunduğumuzda tembel bir şekilde artar. Örneğin:
    • ilk baskıda, extra_memory_committed 0yani henüz hiçbir sayfaya dokunmadık. RSS, 1648 KiBmetin alanı, globaller vb. Gibi normal program başlangıcı için ayrılmış küçük bir dosyadır.
    • ikinci baskıda, 8388608 KiB == 8GiBdeğerli sayfalara yazdık. Sonuç olarak, RSS tam olarak 8GIB'ye yükseltildi.8390256 KiB == 8388608 KiB + 1648 KiB
    • RSS, 8GiB'lik artışlarla artmaya devam ediyor. Son baskı yaklaşık 24 GiB bellek gösteriyor ve 32 GiB yazdırılmadan önce, OOM katili işlemi öldürdü

Ayrıca bakınız: /unix/35129/need-explanation-on-resident-set-size-virtual-size

OOM katil günlükleri

Bizim dmesgkomutları OOM katil günlükleri göstermiştir.

Bunların tam bir yorumu şu şekilde sorulmuştur:

Günlüğün ilk satırı şuydu:

[ 7283.479087] mongod invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

İlginç bir şekilde, dizüstü bilgisayarımda her zaman arka planda OOM katilini tetikleyen MongoDB arka plan programı olduğunu görüyoruz, muhtemelen zavallı şey biraz bellek ayırmaya çalışırken.

Ancak, OOM katili mutlaka uyandıranı öldürmez.

Çağrının ardından, çekirdek aşağıdakileri içeren bir tablo veya işlemler yazdırır oom_score:

[ 7283.479292] [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
[ 7283.479303] [    496]     0   496    16126        6   172032      484             0 systemd-journal
[ 7283.479306] [    505]     0   505     1309        0    45056       52             0 blkmapd
[ 7283.479309] [    513]     0   513    19757        0    57344       55             0 lvmetad
[ 7283.479312] [    516]     0   516     4681        1    61440      444         -1000 systemd-udevd

ve ileride görüyoruz ki main.out, önceki çağrımızda kendi küçüklerimiz gerçekten öldürüldü:

[ 7283.479871] Out of memory: Kill process 15665 (main.out) score 865 or sacrifice child
[ 7283.479879] Killed process 15665 (main.out) total-vm:67111332kB, anon-rss:92kB, file-rss:4kB, shmem-rss:30080832kB
[ 7283.479951] oom_reaper: reaped process 15665 (main.out), now anon-rss:0kB, file-rss:0kB, shmem-rss:30080832kB

Bu günlükte, söz score 865konusu işlemin, muhtemelen şu adreste belirtildiği gibi en yüksek (en kötü) OOM katil skoruna sahip olduğu belirtilmektedir: /unix/153585/how-does-the-oom-killer-decide-which- süreç-to-kill ilk

Ayrıca ilginç bir şekilde, her şey o kadar hızlı oldu ki, serbest hafıza hesaplanmadan önce oom, DeadlineMonitorsüreç tarafından tekrar uyandı :

[ 7283.481043] DeadlineMonitor invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

ve bu sefer genellikle bilgisayarlarımın normal bellek domuzu olan bazı Chromium işlemini öldürdü:

[ 7283.481773] Out of memory: Kill process 11786 (chromium-browse) score 306 or sacrifice child
[ 7283.481833] Killed process 11786 (chromium-browse) total-vm:1813576kB, anon-rss:208804kB, file-rss:0kB, shmem-rss:8380kB
[ 7283.497847] oom_reaper: reaped process 11786 (chromium-browse), now anon-rss:0kB, file-rss:0kB, shmem-rss:8044kB

Ubuntu 19.04, Linux çekirdeği 5.0.0'da test edilmiştir.


8

Sanırım RSS vs VSZ hakkında çok şey söylendi. Bir yönetici / programcı / kullanıcı bakış açısından, uygulamaları tasarladığımda / kodladığımda RSZ, (Yerleşik bellek) hakkında daha fazla endişe duyuyorum ve daha fazla değişken çektiğinizde (yığılı) bu değerin yükseldiğini göreceksiniz. Döngüde malloc tabanlı alan tahsisi oluşturmak için basit bir program deneyin ve bu hatalı alana veri doldurduğunuzdan emin olun. RSS sürekli yükseliyor. VSZ söz konusu olduğunda, linux'un yaptığı daha çok sanal bellek haritalaması ve temel özelliklerinden biri geleneksel işletim sistemi konseptlerinden türetilmiş. VSZ yönetimi, çekirdeğin Sanal bellek yönetimi tarafından yapılır, VSZ hakkında daha fazla bilgi için, Robert Love'ın çekirdekte temel görev_yapısı veri yapısının bir parçası olan mm_struct ve vm_struct açıklamasına bakın.


Love'ın "Linux Çekirdek Geliştirme" adlı kitabından mı bahsediyorsunuz?
benjimin

1

Yönetilmezler, ölçülürler ve muhtemelen sınırlıdırlar (bkz getrlimit. Getrlimit için sistem çağrısı ) (2 ).

RSS, yerleşik set boyutu (sanal adres alanınızın RAM'de oturan kısmı) anlamına gelir .

Proc (5) kullanarak ve durumunu (bellek tüketimi dahil ) kullanarak 1234 işleminin sanal adres alanını sorgulayabilirsiniz.cat /proc/1234/mapscat /proc/1234/status


1
Bu bağlantı soruyu cevaplayabilse de, cevabın temel kısımlarını buraya eklemek ve bağlantıyı referans olarak sağlamak daha iyidir. Bağlantı verilen sayfa değişirse, yalnızca bağlantı yanıtları geçersiz olabilir. - Yorumdan
Maak

İkinci bir link verdim. Bunlardan biri geçerli kalacak
Basile Starynkevitch
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.