2016-05-12 10 views
7

पर साझा स्मृति काम मैं साझा स्मृति पर लिनक्स कर्नेल सीमा में देख रहा थाकैसे लिनक्स

/proc/sys/kernel/shmall 

उन पृष्ठों को आवंटित किया जा सकता है की अधिकतम राशि को निर्दिष्ट करता है पर सीमा है। इस संख्या को x और पेज आकार के रूप में पी के रूप में देखते हुए। मुझे लगता है कि "x * p" बाइट सिस्टम व्यापक साझा स्मृति पर सीमा है।

अब मैं एक साझा स्मृति खंड बनाने के लिए एक छोटा सा कार्यक्रम में लिखा था और मैं उपरोक्त कार्यक्रम ptr में

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); 

नीचे के रूप में दो बार है कि साझा स्मृति खंड से जुड़ी और ptr_info भिन्न थे। इसलिए साझा मेमोरी को मेरी प्रोसेस एड्रेस स्पेस में 2 आभासी पतों पर मैप किया गया है।

ऐसा लगता है कि इस

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

अब shmall सीमा x * p मेरे सवाल में ऊपर बताया गया है के लिए आ रहा जब मैं एक ipcs है। क्या यह सीमा प्रत्येक साझा मेमोरी सेगमेंट के लिए आवंटित सभी वर्चुअल मेमोरी के योग पर लागू होती है? या यह सीमा भौतिक स्मृति पर लागू होती है?

भौतिक स्मृति केवल एक (साझा स्मृति) है और जब मैं 2 shmat करता हूं तो मेरे प्रक्रिया पता स्थान में आवंटित स्मृति की मात्रा से दोगुनी होती है। तो अगर यह एक साझा साझा मेमोरी सेगमेंट पर लगातार shmat है तो यह सीमा जल्द ही हिट हो जाएगी?

उत्तर

1

सीमा केवल भौतिक स्मृति पर लागू होती है, जो सभी खंडों के लिए आवंटित वास्तविक साझा स्मृति है, क्योंकि shmat() केवल नक्शा आवंटित सेगमेंट को प्रोसेस एड्रेस स्पेस में मैप करता है।

आप कर्नेल में यह पता लगा सकते हैं, वहाँ केवल एक ही जगह है जहाँ इस सीमा newseg() function कि नए खंडों (ns->shm_ctlall तुलना) आवंटित में — चेक किया गया है है। shmat() implementation बहुत सारी चीजों से व्यस्त है, लेकिन शमल सीमा के बारे में बिल्कुल परवाह नहीं है, इसलिए आप एक सेगमेंट को जितनी बार चाहें मैप कर सकते हैं (ठीक है, पता स्थान भी सीमित है, लेकिन व्यवहार में आप शायद ही कभी इसकी परवाह करते हैं सीमा नहीं)।

तुम भी इस तरह एक साधारण प्रोग्राम के साथ यूज़रस्पेस से कुछ परीक्षण की कोशिश कर सकते हैं:

#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; 
} 

क्या करता है यह shmall सीमा सिर्फ एक जो वर्तमान प्रणाली है, तो कोशिश करता द्वारा किया जाता है इसके बाद के संस्करण पेज सेट है पेज आकार नया खंड मिलता है और इसे दो बार के नक्शे (सभी सफलतापूर्वक) करने के लिए है, तो एक और पृष्ठ आकार खंड निकलने की कोशिश करता है और ऐसा करने के लिए है कि (कार्यक्रम क्रियान्वित सुपर उपयोगकर्ता के रूप में, क्योंकि यह /proc/sys/kernel/shmall को लिखते हैं) में विफल रहता है:

$ 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

यह एक अच्छी व्याख्या है। मेरे पास कुछ टिप्पणियां हैं। "/ Proc/sys/kernel/shmall" को लिखने में सक्षम होने के लिए इस कार्यक्रम को सुडो के रूप में चलाने की आवश्यकता है। एक और टिप्पणी कार्यक्रम के निष्कर्ष के बाद है, मुझे उम्मीद है कि "/ proc/sys/kernel/shmall" का मान अगले रीबूट तक प्रोग्राम में मान सेट रहता है। लेकिन जब मैं/proc/sys/kernel/shmall पर मान की बिल्ली करता हूं, तो यह अभी भी पुराना मान 18446744073692774399 दिखाता है। क्या आप समझा सकते हैं? – Nuetrino

+0

@ न्यूट्रिनो: ऐसा इसलिए है क्योंकि मैं मूल शमल मूल्य को पुनर्स्थापित कर रहा हूं, यह सिर्फ एक परीक्षण है, इसलिए मुझे लगता है कि इसके बाद आपके पास उचित सिस्टम-डिफ़ॉल्ट मान बेहतर होगा। –

+0

कोड में बिल्कुल नहीं, जहां तक ​​मैं देख सकता हूं कि आप इसे पुनर्स्थापित नहीं करते हैं। – Nuetrino

0

मैं do_shmat समारोह में किसी भी शारीरिक स्मृति आवंटन नहीं मिला (linux/आईपीसी/shm.c)

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

तो Shmat केवल वीएम (अपनी प्रक्रिया पता स्थान) की खपत, का मुख्य कार्य शमत mmap

+0

लेकिन मेरा सवाल अलग है। यह "/ proc/sys/kernel/shmall" द्वारा निर्दिष्ट सीमाओं के बारे में है।क्या यह सभी साझा मेमोरी सेगमेंट के लिए आवंटित सभी वर्चुअल एड्रेस स्पेस के बराबर है या नहीं? यह मेरे लिए पहले से ही स्पष्ट है कि शर्म प्रक्रिया प्रक्रिया स्थान के vm में स्मृति आवंटित करता है। – Nuetrino