2016-05-12 78 views
7

paylaşılan bellek çalışmaları sınırlarını yapar. Bu sayıyı x olarak ve sayfa boyutunu s. "X * p" baytının, sistem genelindeki paylaşılan belleğin sınırı olduğunu varsayalım. nasıl</p> <pre><code>/proc/sys/kernel/shmall </code></pre> <p>tahsis edilebilir sayfaların maksimum miktarı belirtir paylaşılan bellek üzerinde Linux çekirdeği limitleri içine bakıyordu Linux

Şimdi bir paylaşılan bellek segmenti oluşturmak için küçük bir program yazdım ve ben yukarıdaki programda ptr yılında

shm_id = shmget(IPC_PRIVATE, 4*sizeof(int), IPC_CREAT | 0666); 

if (shm_id < 0) { 
    printf("shmget error\n"); 
    exit(1); 
} 
printf("\n The shared memory created is %d",shm_id); 

ptr = shmat(shm_id,NULL,0); 
ptr_info = shmat(shm_id,NULL,0); 

altında iki kat paylaşılan bellek bölümüne bağlanmış ve ptr_info farklıydı. Yani paylaşılan bellek süreç adresimdeki 2 sanal adrese eşlenir. Bir ipcs yaptığınızda bu

... 
0x00000000 1638416 sun  666  16000000 2 
... 

Şimdi x * p soruma yukarıda belirtildiği shmall sınıra geliyor gibi

görünüyor. Bu sınır, her paylaşılan bellek segmenti için ayrılan tüm sanal belleğin toplamı için geçerli midir? veya bu sınır fiziksel hafızaya uygulanır mı?

Fiziksel bellek yalnızca bir tanesidir (paylaşılan bellek) ve 2 shmat yaptığım zaman yukarıdaki programdan işlem adres alanımda ayrılmış bellek miktarının iki katı vardır. Yani bu sınır, tek bir paylaşılan bellek segmentinde sürekli shmat kullanıyor mu?

cevap

1

Bu sınır yalnızca fiziksel bellek için geçerlidir, yani tüm segmentler için ayrılan gerçek paylaşımlı bellek, çünkü shmat() yalnızca ayrılmış segmenti işlem adres boşluğuna eşler. Bu çekirdek içinde iz olabilir

, bu sınır yeni segmentler (ns->shm_ctlall karşılaştırma) ayırır newseg() function içinde — işaretlendiğinde tek bir yer vardır. shmat() implementation birçok şeyle meşgul, ama shmall limitine hiç dikkat etmiyor, böylece bir segmenti istediğiniz kadar çok haritalayabilirsiniz (iyi, adres alanı da sınırlıdır, ancak pratikte bu konuya nadiren bakıyorsunuz) limiti).

Ayrıca bu gibi basit bir programla userspace bazı testi deneyebilirsiniz

:

#define _GNU_SOURCE 
#include <errno.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <unistd.h> 

unsigned long int get_shmall() { 
     FILE *f = NULL; 
     char buf[512]; 
     unsigned long int value = 0; 

     if ((f = fopen("/proc/sys/kernel/shmall", "r")) != NULL) { 
       if (fgets(buf, sizeof(buf), f) != NULL) 
         value = strtoul(buf, NULL, 10); // no proper checks                                        
       fclose(f); // no return value check                                              
     } 
     return value; 
} 

int set_shmall(unsigned long int value) { 
     FILE *f = NULL; 
     char buf[512]; 
     int retval = 0; 

     if ((f = fopen("/proc/sys/kernel/shmall", "w")) != NULL) { 
       if (snprintf(buf, sizeof(buf), "%lu\n", value) >= sizeof(buf) || 
        fwrite(buf, 1, strlen(buf), f) != strlen(buf)) 
         retval = -1; 
       fclose(f); // fingers crossed                                               
     } else 
       retval = -1; 
     return retval; 
} 

int main() 
{ 
     int shm_id1 = -1, shm_id2 = -1; 
     unsigned long int shmall = 0, shmused, newshmall; 
     void *ptr1, *ptr2; 
     struct shm_info shminf; 

     if ((shmall = get_shmall()) == 0) { 
       printf("can't get shmall\n"); 
       goto out; 
     } 
     printf("original shmall: %lu pages\n", shmall); 
     if (shmctl(0, SHM_INFO, (struct shmid_ds *)&shminf) < 0) { 
       printf("can't get SHM_INFO\n"); 
       goto out; 
     } 
     shmused = shminf.shm_tot * getpagesize(); 
     printf("shmused: %lu pages (%lu bytes)\n", shminf.shm_tot, shmused); 
     newshmall = shminf.shm_tot + 1; 
     if (set_shmall(newshmall) != 0) { 
       printf("can't set shmall\n"); 
       goto out; 
     } 
     if (get_shmall() != newshmall) { 
       printf("something went wrong with shmall setting\n"); 
       goto out; 
     } 
     printf("new shmall: %lu pages (%lu bytes)\n", newshmall, newshmall * getpagesize()); 
     printf("shmget() for %u bytes: ", (unsigned int) getpagesize()); 
     shm_id1 = shmget(IPC_PRIVATE, (size_t)getpagesize(), IPC_CREAT | 0666); 
     if (shm_id1 < 0) { 
       printf("failed: %s\n", strerror(errno)); 
       goto out; 
     } 
     printf("ok\nshmat 1: "); 
     ptr1 = shmat(shm_id1, NULL, 0); 
     if (ptr1 == 0) { 
       printf("failed\n"); 
       goto out; 
     } 
     printf("ok\nshmat 2: "); 
     ptr2 = shmat(shm_id1, NULL, 0); 
     if (ptr2 == 0) { 
       printf("failed\n"); 
       goto out; 
     } 
     printf("ok\n"); 
     if (ptr1 == ptr2) { 
       printf("ptr1 and ptr2 are the same with shm_id1\n"); 
       goto out; 
     } 
     printf("shmget() for %u bytes: ", (unsigned int) getpagesize()); 
     shm_id2 = shmget(IPC_PRIVATE, (size_t)getpagesize(), IPC_CREAT | 0666); 
     if (shm_id2 < 0) 
       printf("failed: %s\n", strerror(errno)); 
     else 
       printf("ok, although it's wrong\n"); 
out: 
     if (shmall != 0 && set_shmall(shmall) != 0) 
       printf("failed to restrore shmall\n"); 

     if (shm_id1 >= 0 && shmctl(shm_id1, IPC_RMID, NULL) < 0) 
       printf("failed to remove shm_id1\n"); 

     if (shm_id2 >= 0 && shmctl(shm_id2, IPC_RMID, NULL) < 0) 
       printf("failed to remove shm_id2\n"); 

     return 0; 
} 

şu anda sistemde, daha sonra deneme tarafından kullanılan yukarıda ne shmall sınırı sadece bir sayfasını ayarlar olduğu yapar nedir sayfa büyüklüğünde yeni bir segment almak ve (bütün başarıyla) iki kez eşleştirmek için, daha sonra bir sayfa daha boyutlu bir segment elde etmeye çalışır ve o (o /proc/sys/kernel/shmall yazar çünkü süper kullanıcı olarak programı çalıştırmak) başaramazsa:

$ sudo ./a.out 
original shmall: 18446744073708503040 pages 
shmused: 21053 pages (86233088 bytes) 
new shmall: 21054 pages (86237184 bytes) 
shmget() for 4096 bytes: ok 
shmat 1: ok 
shmat 2: ok 
shmget() for 4096 bytes: failed: No space left on device 
+0

Bu iyi bir açıklama. Birkaç söz var. Bu programın "/ proc/sys/kernel/shmall" yazabilmesi için sudo olarak çalıştırılması gerekiyor. Bir başka nokta ise programın çıkmasından sonra, "/ proc/sys/kernel/shmall" değerinin, bir sonraki yeniden başlatmaya kadar programda ayarlanan değerin beklediğini umuyorum. ama/proc/sys/kernel/shmall değerindeki bir kediyi yaptığımda, hala eski değeri 18446744073692774399 gösterir. Nedenini açıklar mısınız? – Nuetrino

+0

@Nuetrino: çünkü orijinal shmall değerini geri yüklüyorum, sadece bir test, bu yüzden daha sonra sistem varsayılan değerine sahip olsanız iyi olur. –

+0

Kodda tam olarak görmediğim kadarıyla geri yüklemediniz. – Nuetrino

0

Ben

https://github.com/torvalds/linux/blob/5469dc270cd44c451590d40c031e6a71c1f637e8/ipc/shm.c

böylece shmat sadece vm (proses adres alanını) tüketir (linux/ipc/shm.c) ana işlevi do_shmat fonksiyonu herhangi Fiziksel bellek ayırma bulamadık shmat mmap

+0

Ama benim sorum farklı. "/ Proc/sys/kernel/shmall" ile belirtilen sınırlarla ilgilidir.Bu, tüm paylaşılan bellek bölümleri için ayrılmış tüm sanal adres alanlarının toplamını tutar mı? Benim için zaten açık olan shmat, işlem adres boşluğunun vm'sinde bellek ayırır. – Nuetrino