“Otomatik yığın genişletme” nedir?


13

getrlimit (2) kılavuz sayfalarında şu tanımlara sahiptir:

RLIMIT_AS İşlemin sanal belleğinin (adres alanı) bayt cinsinden maksimum boyutu. Bu sınır, bu sınırı aştığında ENOMEM hatasıyla başarısız olan brk (2), mmap (2) ve mremap (2) çağrılarını etkiler. Ayrıca otomatik yığın genişletme başarısız olur (ve sigaltstack (2) aracılığıyla alternatif yığın mevcut değilse, işlemi öldüren bir SIGSEGV üretir). Değer uzun olduğundan, 32 bit uzunluğa sahip makinelerde bu sınır en fazla 2 GiB'dir veya bu kaynak sınırsızdır.

Burada "otomatik yığın genişletme" ile kastedilen nedir? Linux / UNIX ortamındaki yığın gerektiği gibi büyüyor mu? Evet ise, kesin mekanizma nedir?

Yanıtlar:


1

Evet yığınlar dinamik olarak büyür. Yığın, hafızanın üst kısmında, aşağı doğru yığın halinde büyür.

--------------
| Stack      |
--------------
| Free memory|
--------------
| Heap       |
--------------
     .
     .

Yığın yukarı doğru büyür (her malloc yaptığınızda) ve yığın, yeni işlevler çağrıldıkça ve aşağı doğru büyür. Yığın, programın BSS bölümünün hemen üstünde bulunur. Bu, programınızın boyutu ve yığın içindeki belleği allcating şekli de bu işlem için maksimum yığın boyutunu etkiler. Genellikle yığın boyutu sınırsızdır (yığın ve yığın alanları buluşana ve / veya üzerine yazılana kadar yığın taşması ve SIGSEGV :-)

Bu yalnızca kullanıcı işlemleri içindir, Çekirdek yığını her zaman sabittir (genellikle 8KB)


"Genellikle yığın boyutu sınırsızdır", hayır, genellikle 8Mb ( ulimit -s) ile sınırlıdır .
Eddy_Em

evet çoğu sistemde haklısınız. Kabuğun ulimit komutunu kontrol ediyorsanız, yığın boyutunda sınırsız olan (ulimit -Hs) sabit bir sınır vardır. Her neyse, bu nokta, yığın ve yığının zıt yönlerde büyüdüğünü vurgulamaktı.
Santosh

Öyleyse, "otomatik genişleme" öğelerinin yığına itilmesinden nasıl farklıdır? Açıklamanızdan, aynı olduklarını hissediyorum. Ayrıca, yığının ve yığının başlangıç ​​noktalarının 8MB'den fazla olduğunu hissettim, bu yüzden yığın gerektiği kadar büyüyebilir (veya yığına çarpar). Bu doğru mu? Evet ise, işletim sistemi yığının ve yığının nereye yerleştirileceğine nasıl karar verir?
loudandclear

Bunlar aynıdır, ancak rlimit kullanarak boyutu sınırlamadığınız sürece yığınların sabit bir boyutu yoktur. Yığın, sanal bellek alanının sonuna yerleştirilir ve yığın, yürütülebilir dosyanın veri bölümünden hemen sonra gelir.
Santosh

Anladım, teşekkürler. Ancak, "yığınlar sabit boyutu yok" bölümünü almak sanmıyorum. Bu durumda, 8Mb yumuşak sınırı ne işe yarıyor?
loudandclear

8

Tam mekanizması Linux üzerinde, burada verilmektedir: in anonim eşleştirmeleri bir sayfa hatasına taşıma Eğer bir "yetişkin bir tahsisat yok" olup olmadığını görmek için kontrol , bir yığını gibi genişletmek gerektiğini söyledi. VM alan kaydı yapmanız gerektiğini söylüyorsa, yığını genişletmek için başlangıç ​​adresini ayarlarsınız.

Bir sayfa hatası meydana geldiğinde, adrese bağlı olarak, yığının genişletilmesi yoluyla servis edilebilir (ve hata bozulabilir). Sanal bellek için bu "hata üzerinde aşağı doğru" davranışı, MAP_GROWSDOWNbayrak mmapsistem çağrısına geçirilen rasgele kullanıcı programları tarafından istenebilir .

Bir kullanıcı programında da bu mekanizma ile uğraşabilirsiniz:

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>

int main() {
        long page_size = sysconf(_SC_PAGE_SIZE);
        void *mem = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_GROWSDOWN|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
        if (MAP_FAILED == mem) {
                perror("failed to create growsdown mapping");
                return EXIT_FAILURE;
        }

        volatile char *tos = (char *) mem + page_size;

        int i;
        for (i = 1; i < 10 * page_size; ++i)
                tos[-i] = 42;

        fprintf(stderr, "inspect mappping for originally page-sized %p in /proc... press any key to continue...\n", mem);
        (void) getchar();

        if (munmap(mem, page_size))
                perror("failed munmap");

        return EXIT_SUCCESS;
}

İstendiğinde, programın pidini bulursunuz (üzerinden ps) ve /proc/$THAT_PID/mapsorijinal alanın nasıl büyüdüğüne bakın.


Bellek bölgesi MAP_GROWSDOWN üzerinden büyümüş olsa bile orijinal mem için munmap ve page_size çağırmak uygun mudur? Evet, çünkü aksi takdirde kullanmak çok karmaşık bir API olurdu, ancak belgeler bu konuda açıkça bir şey söylemiyor
i.petruk

2
MAP_GROWSDOWN kullanılmamalıdır ve glibc'den kaldırılmıştır ( neden için lwn.net/Articles/294001 adresine bakın ).
Collin
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.