क्या लिनक्स "रैम से रन आउट" हो सकता है?


20

मैंने लोगों की वेब के आसपास कई पोस्ट देखीं, जो कि एक होस्टेड VPS की अप्रत्याशित रूप से हत्या की प्रक्रियाओं के बारे में शिकायत कर रही थीं क्योंकि उन्होंने बहुत अधिक RAM का उपयोग किया था।

यह कैसे हो सकता है? मैंने सोचा था कि सभी आधुनिक ओएस '' भौतिक रैम पर जो भी जाते हैं, उसके लिए डिस्क स्वैप का उपयोग करके "असीम रैम" प्रदान करते हैं। क्या ये सही है?

यदि एक प्रक्रिया "कम रैम के कारण मार दी जाती है" तो क्या हो सकता है?


12
किसी भी OS में असीम RAM नहीं होती है। मशीन में भौतिक रैम चिप्स के अलावा, ओएस - आमतौर पर, वैकल्पिक रूप से - तथाकथित 'स्वैप फ़ाइल' का उपयोग कर सकते हैं जो डिस्क पर है। जब एक कंप्यूटर को रैम स्टिक्स में अधिक मेमोरी की आवश्यकता होती है, तो वह स्वैप फ़ाइल में कुछ सामान स्वैप करता है। लेकिन जैसे-जैसे स्वैप फाइल पहुंचती है यह क्षमता हो जाती है - या तो क्योंकि आप अधिकतम आकार (विशिष्ट) सेट करते हैं या डिस्क भरता है - आप वर्चुअल मेमोरी से बाहर निकलते हैं।
जॉन डिब्लिंग

@JohnDibling; तो क्या कोई कारण है कि कोई फ़ाइल सिस्टम के लिए डिस्क स्थान को बचाने के अलावा स्वैप आकार को सीमित करना चाहेगा? दूसरे शब्दों में अगर मेरे पास 20GB डिस्क और केवल 1GB फाइलें हैं, तो क्या मेरे स्वैप आकार को 19GB में सेट नहीं करने का कोई कारण है?
उनके सिर

1
चीजों की निगरानी के लिए, मैं कहूंगा कि स्वैप का आकार सीमित करने के दो कारण हैं) डिस्क की खपत को कम करना और 2) प्रदर्शन को बढ़ाना। उत्तरार्द्ध विंडोज के तहत / * NIX से अधिक सच हो सकता है, लेकिन फिर, यदि आप अपने डिस्क पर स्वैप स्थान का उपयोग कर रहे हैं, तो आपका प्रदर्शन नीचा है। डिस्क की पहुंच या तो RAM से धीमी होती है, या सिस्टम की तुलना में RAM से बहुत धीमी होती है।
जॉन डिब्लिंग

9
स्वैप रैम नहीं हैen.wikipedia.org/wiki/Random-access_memory आपके सिस्टम में RAM की मात्रा आपके सिस्टम की अवधि में RAM की मात्रा है। यह अस्पष्ट या गतिशील मात्रा नहीं है। यह बिल्कुल तय है। "मेमोरी" एक अधिक अस्पष्ट अवधारणा है, लेकिन रैम और भंडारण के अन्य रूपों के बीच का अंतर है, क्योंकि टेर्डन (+1) बताते हैं, बहुत महत्वपूर्ण है। परिमाण के कई आदेशों द्वारा रैम के प्रदर्शन के लिए डिस्क स्वैप स्थानापन्न नहीं कर सकता है । एक प्रणाली जो स्वैप पर अत्यधिक निर्भर करती है वह सबसे अच्छा अस्थायी और सामान्य रूप से होती है: कचरा।
गोल्डीलॉक्स

1
तो डिस्क स्थान अब अनंत है?
कज़

जवाबों:


41

यदि एक प्रक्रिया "कम रैम के कारण मार दी जाती है" तो क्या हो सकता है?

यह कभी-कभी कहा जाता है कि डिफ़ॉल्ट रूप से लिनक्स कभी भी एप्लिकेशन कोड से अधिक मेमोरी के अनुरोधों से इनकार नहीं करता है - जैसे malloc()1 यह वास्तव में सच नहीं है; डिफ़ॉल्ट एक अनुमानी का उपयोग करता है जिससे

पता स्थान के स्पष्ट overcommits मना कर दिया जाता है। एक विशिष्ट प्रणाली के लिए उपयोग किया जाता है। यह ओवरलैपिट को स्वैप उपयोग को कम करने की अनुमति देते समय एक गंभीर रूप से जंगली आवंटन सुनिश्चित करता है।

से [linux_src]/Documentation/vm/overcommit-accounting(सभी उद्धरण 3.11 पेड़ से हैं)। वास्तव में "गंभीर रूप से जंगली आवंटन" के रूप में जो मायने रखता है वह स्पष्ट नहीं किया गया है, इसलिए हमें विवरण निर्धारित करने के लिए स्रोत से गुजरना होगा। हम फुटनोट 2 (नीचे) में प्रयोगात्मक विधि का उपयोग करने की कोशिश कर सकते हैं और हेयुरिस्टिक के कुछ प्रतिबिंब प्राप्त कर सकते हैं - इसके आधार पर, मेरा प्रारंभिक अनुभवजन्य अवलोकन यह है कि आदर्श परिस्थितियों में (== प्रणाली निष्क्रिय है), यदि आप डॉन ' t में कोई स्वैप है, आपको लगभग आधी RAM आवंटित करने की अनुमति होगी, और यदि आपके पास स्वैप है, तो आपको लगभग आधा RAM और आपके सभी स्वैप मिल जाएंगे। यही कारण है कि कम या ज्यादा है प्रक्रिया के अनुसार (लेकिन ध्यान दें कि यह सीमा है , गतिशील और क्योंकि राज्य के परिवर्तन के अधीन, फुटनोट 5 में कुछ टिप्पणियों को देखें)।

आधा आपका रैम प्लस स्वैप स्पष्ट रूप से "कमिटिमिट" फ़ील्ड के लिए डिफ़ॉल्ट है /proc/meminfo। यहाँ इसका क्या अर्थ है - और ध्यान दें कि इसका वास्तव में चर्चा की गई सीमा से कोई लेना-देना नहीं है [src]/Documentation/filesystems/proc.txt:

कमिटमेंट: ओवरकमिटी अनुपात ('vm.overcommit_ratio') के आधार पर, यह वर्तमान में सिस्टम पर आवंटित की जाने वाली मेमोरी की कुल राशि है। यह सीमा केवल तभी मनाई जाती है जब सख्त ओवरकॉमिटिंग अकाउंटिंग सक्षम हो (मोड 2 इन 'vm.overcommit_memory/)। कमेटीमिट की गणना निम्न सूत्र से की जाती है: कमिटमिट = ('vm.overcommit_ratio' * फिजिकल रैम) + स्वैप उदाहरण के लिए, एक सिस्टम पर फिजिकल रैम के 1G और 30G के 'vm.overcommit_ratio' के साथ स्वैप का 7G होगा। 7.3G का एक कमिटमेंट।

पहले से उद्धृत ओवरकमिट-अकाउंटिंग डॉक में कहा गया है कि डिफ़ॉल्ट vm.overcommit_ratio50 है। इसलिए यदि आप sysctl vm.overcommit_memory=2, आप तब vm.covercommit_ratio (साथ sysctl) समायोजित कर सकते हैं और परिणाम देख सकते हैं। 3 डिफ़ॉल्ट मोड, जब CommitLimitलागू नहीं किया जाता है और केवल "पता स्थान के स्पष्ट overcommits मना कर दिया जाता है", जब है vm.overcommit_memory=0

जबकि डिफ़ॉल्ट रणनीति में "गंभीर रूप से जंगली आवंटन" को रोकने के लिए एक अनुमानी प्रति-प्रक्रिया सीमा होती है, यह सिस्टम को गंभीर रूप से जंगली, आवंटन वार प्राप्त करने के लिए पूरी तरह से स्वतंत्र छोड़ देता है। 4 इसका मतलब कुछ बिंदु पर यह मेमोरी से बाहर निकल सकता है और OOM हत्यारे के माध्यम से कुछ प्रक्रिया (तों) को दिवालिया घोषित करना होगा ।

OOM हत्यारा क्या मारता है? जरूरी नहीं कि स्मृति के लिए पूछी जाने वाली प्रक्रिया कोई भी हो, क्योंकि जरूरी नहीं कि वास्तव में दोषी प्रक्रिया हो, और इससे भी महत्वपूर्ण बात यह हो कि जरूरी नहीं कि जो सिस्टम सबसे ज्यादा समस्या से बाहर निकलेगा।

यह यहाँ से उद्धृत है जो संभवतः एक 2.6.x स्रोत का हवाला देता है:

/*
 * oom_badness - calculate a numeric value for how bad this task has been
 *
 * The formula used is relatively simple and documented inline in the
 * function. The main rationale is that we want to select a good task
 * to kill when we run out of memory.
 *
 * Good in this context means that:
 * 1) we lose the minimum amount of work done
 * 2) we recover a large amount of memory
 * 3) we don't kill anything innocent of eating tons of memory
 * 4) we want to kill the minimum amount of processes (one)
 * 5) we try to kill the process the user expects us to kill, this
 *    algorithm has been meticulously tuned to meet the principle
 *    of least surprise ... (be careful when you change it)
 */

जो एक सभ्य तर्क की तरह लगता है। हालांकि, फोरेंसिक प्राप्त किए बिना, # 5 (जो # 1 के लिए अतिरेक है) एक कठिन बिक्री कार्यान्वयन बुद्धिमान की तरह लगता है, और # 3 # 2 के बेमानी है। तो यह समझ में आ सकता है कि इस विलेख को # 2/3 और # 4 से नीचे रखा गया है।

मैंने हाल के एक स्रोत (3.11) के माध्यम से पकड़ लिया और देखा कि यह टिप्पणी अंतरिम में बदल गई है:

/**
 * oom_badness - heuristic function to determine which candidate task to kill
 *
 * The heuristic for determining which task to kill is made to be as simple and
 * predictable as possible.  The goal is to return the highest value for the
 * task consuming the most memory to avoid subsequent oom failures.
 */

यह # 2 के बारे में थोड़ा और स्पष्ट रूप से है: "लक्ष्य [मारना है] बाद की ऊम विफलताओं से बचने के लिए सबसे अधिक मेमोरी का उपभोग करने वाला कार्य," और निहितार्थ # 4 ( "हम प्रक्रियाओं की न्यूनतम मात्रा ( एक ) को मारना चाहते हैं" ) ) का है

यदि आप OOM हत्यारे को कार्रवाई में देखना चाहते हैं, तो फुटनोट 5 देखें।


1 एक भ्रम गाइल्स ने मुझे धन्यवाद दिया, टिप्पणी देखें।


2 यहाँ C का एक सीधा सा हिस्सा है, जो यह निर्धारित करने के लिए मेमोरी की बड़ी मात्रा में वृद्धि के लिए कहता है कि कब अधिक के लिए एक अनुरोध विफल हो जाएगा:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define MB 1 << 20

int main (void) {
    uint64_t bytes = MB;
    void *p = malloc(bytes);
    while (p) {
        fprintf (stderr,
            "%lu kB allocated.\n",
            bytes / 1024
        );
        free(p);
        bytes += MB;
        p = malloc(bytes);
    }
    fprintf (stderr,
        "Failed at %lu kB.\n",
        bytes / 1024
    );
    return 0;
}            

यदि आप C को नहीं जानते हैं, तो आप इसे संकलित कर सकते हैं gcc virtlimitcheck.c -o virtlimitcheck, फिर चला सकते हैं ./virtlimitcheck। यह पूरी तरह से हानिरहित है, क्योंकि यह प्रक्रिया किसी भी स्थान का उपयोग नहीं करती है जो इसके लिए पूछता है - यानी, यह वास्तव में किसी भी रैम का उपयोग नहीं करता है।

4 जीबी सिस्टम और 6 जीबी स्वैप के साथ 3.11 x86_64 सिस्टम पर, मैं ~ 7400000 केबी पर विफल रहा; संख्या में उतार-चढ़ाव होता है, इसलिए शायद राज्य एक कारक है। यह संयोग के करीब है CommitLimitमें /proc/meminfoहै, लेकिन इस के माध्यम से संशोधित vm.overcommit_ratioकोई फर्क नहीं है। 64 एमबी स्वैप के साथ 3.6.11 32-बिट एआरएम 448 एमबी प्रणाली पर, हालांकि, मैं ~ 230 एमबी पर विफल रहता हूं। यह दिलचस्प है क्योंकि पहले मामले में यह राशि रैम की मात्रा लगभग दोगुनी है, जबकि दूसरे में यह लगभग 1/4 है - जो कि स्वैप की मात्रा को दृढ़ता से लागू करना एक कारक है। पहली प्रणाली को स्वैप बंद करके इसकी पुष्टि की गई थी, जब विफलता सीमा ~ 1.95 जीबी हो गई, थोड़ा एआरएम बॉक्स के समान अनुपात।

लेकिन क्या यह वास्तव में प्रति प्रक्रिया है? यह प्रतीत होता है। नीचे दिया गया छोटा प्रोग्राम उपयोगकर्ता के लिए मेमोरी का एक हिस्सा निर्धारित करता है, और यदि यह सफल होता है, तो आपको रिटर्न हिट करने के लिए इंतजार करता है - इस तरह से आप एक साथ कई उदाहरणों की कोशिश कर सकते हैं:

#include <stdio.h>
#include <stdlib.h>

#define MB 1 << 20

int main (int argc, const char *argv[]) {
    unsigned long int megabytes = strtoul(argv[1], NULL, 10);
    void *p = malloc(megabytes * MB);
    fprintf(stderr,"Allocating %lu MB...", megabytes);
    if (!p) fprintf(stderr,"fail.");
    else {
        fprintf(stderr,"success.");
        getchar();
        free(p);
    }
    return 0;
}

हालांकि, सावधान रहें कि यह रैम की मात्रा के बारे में कड़ाई से नहीं है और उपयोग की परवाह किए बिना स्वैप - सिस्टम स्थिति के प्रभावों के बारे में टिप्पणियों के लिए फुटनोट 5 देखें।


3 सिस्टम केCommitLimit लिए अनुमत पता स्थान की मात्रा को संदर्भित करता है जब vm.overcommit_memory = 2. संभवत: तब, आप जितनी राशि आवंटित कर सकते हैं, वह न्यूनतम होनी चाहिए जो पहले से ही प्रतिबद्ध है, जो कि स्पष्ट रूप से Committed_ASक्षेत्र है।

एक संभावित दिलचस्प प्रयोग यह प्रदर्शित करता है #include <unistd.h>कि सदाशिवचिट्ठ के शीर्ष (फुटनोट 2 देखें), और लूप fork()से ठीक पहले जोड़ने के लिए है while()। यह कुछ थकाऊ तुल्यकालन के बिना यहाँ वर्णित के रूप में काम करने की गारंटी नहीं है, लेकिन यह एक अच्छा मौका होगा, YMMV:

> sysctl vm.overcommit_memory=2
vm.overcommit_memory = 2
> cat /proc/meminfo | grep Commit
CommitLimit:     9231660 kB
Committed_AS:    3141440 kB
> ./virtlimitcheck 2&> tmp.txt
> cat tmp.txt | grep Failed
Failed at 3051520 kB.
Failed at 6099968 kB.

यह समझ में आता है - tmp.txt को विस्तार से देखते हुए आप प्रक्रियाओं को उनके बड़े और बड़े आवंटन को वैकल्पिक रूप से देख सकते हैं (यह आसान है यदि आप आउटपुट में पिड फेंकते हैं), एक तक, जाहिर है, पर्याप्त दावा किया है कि दूसरा विफल रहता है। विजेता तब सब कुछ CommitLimitमाइनस तक हड़पने के लिए स्वतंत्र है Committed_AS


4 यह ध्यान देने योग्य बात है, इस बिंदु पर, यदि आप पहले से ही वर्चुअल एड्रेसिंग और डिमांड पेजिंग को नहीं समझते हैं, तो यह कि पहली जगह पर प्रतिबद्धता के बारे में क्या संभव है कि कर्नेल उपयोगकर्ता प्रक्रियाओं को आवंटित करता है, यह शारीरिक मेमोरी नहीं है - यह वर्चुअल एड्रेस स्पेस । उदाहरण के लिए, यदि कोई प्रक्रिया किसी चीज़ के लिए 10 एमबी रखती है, तो उसे (आभासी) पतों के अनुक्रम के रूप में रखा जाता है, लेकिन वे पते अभी तक भौतिक स्मृति के अनुरूप नहीं हैं। जब ऐसा पता एक्सेस किया जाता है, तो इसका परिणाम पृष्ठ दोष होता हैऔर फिर कर्नेल इसे वास्तविक मेमोरी पर मैप करने का प्रयास करता है ताकि यह एक वास्तविक मूल्य स्टोर कर सके। प्रक्रियाएं आमतौर पर बहुत अधिक आभासी स्थान आरक्षित करती हैं, क्योंकि वे वास्तव में उपयोग करते हैं, जो कर्नेल को रैम का सबसे कुशल उपयोग करने की अनुमति देता है। हालाँकि, भौतिक मेमोरी अभी भी एक सीमित संसाधन है और जब सभी को वर्चुअल एड्रेस स्पेस में मैप कर दिया गया है, तो कुछ रैम को खाली करने के लिए कुछ वर्चुअल एड्रेस स्पेस को खत्म करना होगा।


5 पहली चेतावनी : यदि आप इसके साथ प्रयास करते हैं vm.overcommit_memory=0, तो सुनिश्चित करें कि आप पहले अपना काम बचा लें और किसी भी महत्वपूर्ण एप्लिकेशन को बंद कर दें, क्योंकि सिस्टम ~ 90 सेकंड के लिए फ्रीज हो जाएगा और कुछ प्रक्रिया मर जाएगी!

यह विचार एक कांटा बम चलाने का है जो 90 सेकंड के बाद बाहर निकलता है, कांटे अंतरिक्ष आवंटित करते हैं और उनमें से कुछ रैम को बड़ी मात्रा में डेटा लिखते हैं, जबकि सभी stderr को रिपोर्ट करते हैं।

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>

/* 90 second "Verbose hungry fork bomb".
Verbose -> It jabbers.
Hungry -> It grabs address space, and it tries to eat memory.

BEWARE: ON A SYSTEM WITH 'vm.overcommit_memory=0', THIS WILL FREEZE EVERYTHING
FOR THE DURATION AND CAUSE THE OOM KILLER TO BE INVOKED.  CLOSE THINGS YOU CARE
ABOUT BEFORE RUNNING THIS. */

#define STEP 1 << 30 // 1 GB
#define DURATION 90

time_t now () {
    struct timeval t;
    if (gettimeofday(&t, NULL) == -1) {
        fprintf(stderr,"gettimeofday() fail: %s\n", strerror(errno));
        return 0;
    }
    return t.tv_sec;
}

int main (void) {
    int forks = 0;
    int i;
    unsigned char *p;
    pid_t pid, self;
    time_t check;
    const time_t start = now();
    if (!start) return 1;

    while (1) {
    // Get our pid and check the elapsed time.
        self = getpid();
        check = now();
        if (!check || check - start > DURATION) return 0;
        fprintf(stderr,"%d says %d forks\n", self, forks++);
    // Fork; the child should get its correct pid.
        pid = fork();
        if (!pid) self = getpid();
    // Allocate a big chunk of space.
        p = malloc(STEP);
        if (!p) {
            fprintf(stderr, "%d Allocation failed!\n", self);
            return 0;
        }
        fprintf(stderr,"%d Allocation succeeded.\n", self);
    // The child will attempt to use the allocated space.  Using only
    // the child allows the fork bomb to proceed properly.
        if (!pid) {
            for (i = 0; i < STEP; i++) p[i] = i % 256;
            fprintf(stderr,"%d WROTE 1 GB\n", self);
        }
    }
}                        

इसे संकलित करें gcc forkbomb.c -o forkbomb। सबसे पहले, इसे आजमाएँ sysctl vm.overcommit_memory=2- आपको शायद कुछ मिल जाएगा:

6520 says 0 forks
6520 Allocation succeeded.
6520 says 1 forks
6520 Allocation succeeded.
6520 says 2 forks
6521 Allocation succeeded.
6520 Allocation succeeded.
6520 says 3 forks
6520 Allocation failed!
6522 Allocation succeeded.

इस वातावरण में, इस तरह का कांटा बम बहुत दूर नहीं मिलता है। ध्यान दें कि "एन फोर्क्स" में संख्या प्रक्रियाओं की कुल संख्या नहीं है, यह श्रृंखला / शाखा में प्रक्रियाओं की संख्या है जो उस तक जाती है।

अब इसके साथ प्रयास करें vm.overcommit_memory=0। यदि आप किसी फ़ाइल में स्टेटर को पुनर्निर्देशित करते हैं, तो आप बाद में कुछ कच्चे विश्लेषण कर सकते हैं, जैसे:

> cat tmp.txt | grep failed
4641 Allocation failed!
4646 Allocation failed!
4642 Allocation failed!
4647 Allocation failed!
4649 Allocation failed!
4644 Allocation failed!
4643 Allocation failed!
4648 Allocation failed!
4669 Allocation failed!
4696 Allocation failed!
4695 Allocation failed!
4716 Allocation failed!
4721 Allocation failed!

प्रदर्शन कि overcommit_memory = 0 के लिए अनुमानी - केवल 15 प्रक्रियाओं 1 जीबी का आवंटन करने में विफल रहा है राज्य से प्रभावित। कितनी प्रक्रियाएँ थीं? Tmp.txt के अंत को देखते हुए, शायद> 100,000। अब वास्तव में 1 जीबी का उपयोग कैसे किया जा सकता है?

> cat tmp.txt | grep WROTE
4646 WROTE 1 GB
4648 WROTE 1 GB
4671 WROTE 1 GB
4687 WROTE 1 GB
4694 WROTE 1 GB
4696 WROTE 1 GB
4716 WROTE 1 GB
4721 WROTE 1 GB

आठ - जो फिर से समझ में आता है, क्योंकि उस समय मेरे पास ~ 3 जीबी रैम मुफ्त और 6 जीबी स्वैप था।

ऐसा करने के बाद अपने सिस्टम लॉग पर एक नज़र डालें। आपको OOM किलर रिपोर्टिंग स्कोर (अन्य चीजों के बीच) देखना चाहिए; संभवतः इससे संबंधित है oom_badness


प्रतिबद्धता से अधिक स्मृति को स्वैप करना कोई समाधान नहीं है (या संबंधित भी)। मेमोरी एलोकेशन (जैसे: मॉलोक) वर्चुअल मेमोरी को आरक्षित करने का अनुरोध करने के बारे में है, भौतिक रूप से नहीं।
जूलियाग्रे

1
@ जैलग्रे: "प्रतिबद्धता से अधिक स्मृति के लिए स्वैपिंग एक समाधान (या यहां तक ​​कि संबंधित नहीं है)" -> हां, वास्तव में यह है। आमतौर पर उपयोग किए जाने वाले पृष्ठों को रैम से अदला-बदली किया जाता है, जिससे पेजिंग दोष / आवंटन (जो कि अधिक प्रतिबद्धता संभव बनाता है) के कारण पृष्ठ दोषों से निपटने के लिए अधिक रैम उपलब्ध है। स्वैप किए गए पृष्ठों को कुछ समय में रैम में वापस मांगने की आवश्यकता हो सकती है।
गोल्डीलॉक्स 27'13

"मेमोरी एलोकेशन (जैसे: मॉलोक) वर्चुअल मेमोरी को आरक्षित करने का अनुरोध करने के बारे में है, भौतिक रूप से नहीं।" -> सही है, लेकिन जब कोई भौतिक मैपिंग शेष नहीं है, तो कर्नेल (और वैकल्पिक रूप से, नहीं) कह सकता है । यह निश्चित रूप से नहीं होगा क्योंकि एक प्रक्रिया वर्चुअल एड्रेस स्पेस से बाहर चली गई है (या कम से कम आमतौर पर नहीं, क्योंकि यह संभव है, कम से कम 32-बिट सिस्टम पर भी)।
गोल्डीलॉक्स

डिमांड पेजिंग वह नहीं है जो प्रतिबद्धता पर स्मृति को संभव बनाता है। लिनक्स निश्चित रूप से सिस्टम पर कोई स्वैप क्षेत्र के साथ स्मृति पर प्रतिबद्ध है। आप प्रतिबद्धता और मांग पेजिंग पर स्मृति को भ्रमित कर सकते हैं। यदि लिनक्स 64% बिट प्रक्रिया के साथ मॉलॉक के लिए "नहीं" कहता है, अर्थात यदि इसे हमेशा ओवरकॉमिट करने के लिए कॉन्फ़िगर नहीं किया गया है, तो यह या तो स्मृति भ्रष्टाचार के कारण होगा या क्योंकि सभी मेमोरी आरक्षणों का योग (रैम या डिस्क के लिए मैप किया गया है या नहीं) विन्यास के आधार पर एक सीमा से अधिक है। यह राम के उपयोग के साथ कुछ नहीं करना है क्योंकि यह तब भी हो सकता है जबकि अभी भी मुफ्त रैम है।
जुलियाग्रे

"मांग पेजिंग वह नहीं है जो प्रतिबद्धता पर स्मृति को संभव बनाता है।" -> शायद यह कहना बेहतर होगा कि यह वर्चुअल एड्रेसिंग है जो मांग को पेजिंग और प्रतिबद्धता से अधिक संभव बनाता है। "लिनक्स निश्चित रूप से बिना किसी स्वैप क्षेत्र के साथ सिस्टम पर मेमोरी को खत्म कर देता है।" -> जाहिर है, चूंकि मांग पेजिंग को स्वैप की आवश्यकता नहीं है; स्वैप से मांग पेजिंग मांग का एक विशेष उदाहरण है। एक बार फिर, स्वैप है से अधिक प्रतिबद्धता के लिए एक समाधान, इस अर्थ में कि यह समस्या का हल नहीं है, लेकिन समझ में संभावित OOM घटनाओं प्रतिबद्धता भर से प्रभावित हो सकती है को रोकने में मदद मिलेगी कि में।
गोल्डीलॉक्स

16

यह आपके साथ नहीं होगा यदि आप केवल 1G डेटा को मेमोरी में लोड करते हैं। क्या होगा यदि आप बहुत अधिक लोड करते हैं? उदाहरण के लिए, मैं अक्सर लाखों संभावनाओं वाली बड़ी फ़ाइलों के साथ काम करता हूं जिन्हें आर में लोड करने की आवश्यकता होती है। इसमें लगभग 16GB रैम लगती है।

मेरे लैपटॉप पर उपरोक्त प्रक्रिया को चलाने से यह पागलों की तरह गमागमन करना शुरू कर देगा जैसे ही मेरी 8 जीबी की रैम भरी गई है। यह, बदले में, सब कुछ धीमा कर देगा क्योंकि डिस्क से पढ़ना रैम से पढ़ने की तुलना में बहुत धीमा है। क्या होगा यदि मेरे पास 2GB रैम और केवल 10GB मुक्त स्थान वाला लैपटॉप है? एक बार जब प्रक्रिया ने सभी रैम को ले लिया है, तो यह डिस्क को भी भर देगा क्योंकि यह स्वैप करने के लिए लिख रहा है और मुझे और अधिक रैम के साथ नहीं छोड़ा गया है और स्वैप करने के लिए अधिक जगह नहीं है (लोग स्वैप को सीमित करने के बजाय एक समर्पित विभाजन के लिए करते हैं। ठीक उसी कारण के लिए स्वैप)। यही वह जगह है जहां ओओएम हत्यारा अंदर आता है और प्रक्रियाओं को मारना शुरू कर देता है।

तो, सिस्टम वास्तव में मेमोरी से बाहर चला सकता है। इसके अलावा, स्वैपिंग के कारण धीमी गति से I / O संचालन के कारण भारी स्वैपिंग सिस्टम अनुपयोगी हो सकते हैं। एक आम तौर पर जितना संभव हो उतना गमागमन से बचना चाहता है। तेज एसएसडी वाले उच्च अंत सर्वरों पर भी प्रदर्शन में स्पष्ट कमी है। मेरे लैपटॉप पर, जिसमें क्लासिक 7200RPM ड्राइव है, कोई भी महत्वपूर्ण स्वैपिंग अनिवार्य रूप से सिस्टम को अनुपयोगी बनाता है। जितना अधिक यह स्वैप होता है, उतना ही धीमा हो जाता है। अगर मैं आक्रामक प्रक्रिया को जल्दी से नहीं मारता हूं, तो ओओएम हत्यारे के कदमों तक सब कुछ लटका रहता है।


5

अधिक रैम नहीं होने पर प्रक्रियाओं को मार नहीं दिया जाता है, जब वे इस तरह से ठगे जाते हैं तो उन्हें मार दिया जाता है:

  • लिनक्स कर्नेल आमतौर पर प्रक्रियाओं को आवंटित करने की अनुमति देता है (यानी आरक्षित) वर्चुअल मेमोरी की मात्रा जो कि वास्तव में उपलब्ध है (रैम + सभी स्वैप क्षेत्र का हिस्सा) की तुलना में बड़ी है।
  • जब तक प्रक्रियाएं केवल उनके द्वारा आरक्षित पृष्ठों के सबसेट तक पहुंचती हैं, तब तक सब कुछ ठीक चलता है।
  • अगर कुछ समय बाद, एक प्रक्रिया उस पृष्ठ तक पहुंचने का प्रयास करती है जिसका वह मालिक होता है, लेकिन अधिक पृष्ठ मुक्त नहीं होते हैं, तो स्मृति की स्थिति समाप्त हो जाती है
  • OOM हत्यारा प्रक्रियाओं में से एक का चयन करता है, जरूरी नहीं कि वह जो एक नए पृष्ठ का अनुरोध करता है, और वर्चुअल मेमोरी को पुनर्प्राप्त करने के लिए इसे मार देता है।

यह तब भी हो सकता है जब सिस्टम सक्रिय रूप से स्वैप नहीं कर रहा है, उदाहरण के लिए यदि स्वैप क्षेत्र नींद डेमन मेमोरी पृष्ठों से भरा है।

यह OSes पर कभी नहीं होता है जो मेमोरी को ओवरकम नहीं करता है। उनके साथ कोई भी यादृच्छिक प्रक्रिया नहीं मारी जाती है, लेकिन आभासी स्मृति के लिए पूछने वाली पहली प्रक्रिया में त्रुटि होने पर मॉलॉक (या समान) वापस आ जाता है। इस प्रकार यह स्थिति को ठीक से संभालने का मौका दिया जाता है। हालाँकि, इन OSes पर, यह भी हो सकता है कि सिस्टम वर्चुअल मेमोरी से बाहर चला जाए, जबकि अभी भी मुफ्त रैम है, जो काफी भ्रामक है और आम तौर पर गलत समझा जाता है।


3

जब उपलब्ध रैम समाप्त हो जाती है, तो कर्नेल डिस्क पर प्रसंस्करण के बिट्स को स्वैप करना शुरू कर देता है। वास्तव में, जब RAM थकावट के पास होता है तो कर्नेल स्वैप करना शुरू कर देता है: निष्क्रिय समय होने पर यह लगातार स्वैप करना शुरू कर देता है, इसलिए यदि किसी एप्लिकेशन को अचानक अधिक मेमोरी की आवश्यकता होती है, तो अधिक उत्तरदायी होना चाहिए।

ध्यान दें कि रैम का उपयोग केवल प्रक्रियाओं की मेमोरी को स्टोर करने के लिए नहीं किया जाता है। एक सामान्य स्वस्थ प्रणाली पर, लगभग आधे रैम का उपयोग प्रक्रियाओं द्वारा किया जाता है, और दूसरे आधे का उपयोग डिस्क कैश और बफ़र्स के लिए किया जाता है। यह चल रही प्रक्रियाओं और फ़ाइल इनपुट / आउटपुट के बीच एक अच्छा संतुलन प्रदान करता है।

स्वैप स्पेस अनंत नहीं है। कुछ बिंदु पर, यदि प्रक्रियाएं अधिक से अधिक मेमोरी आवंटित करती रहती हैं, तो रैम से स्पिलओवर डेटा स्वैप को भर देगा। जब ऐसा होता है, तो ऐसी प्रक्रियाएं जो अधिक मेमोरी का अनुरोध करने का प्रयास करती हैं, उनके अनुरोध को अस्वीकार कर दिया जाता है।

डिफ़ॉल्ट रूप से, लिनक्स मेमोरी को ओवरकम कर देता है। इसका मतलब यह है कि यह कभी-कभी एक प्रक्रिया को स्मृति के साथ चलने की अनुमति देगा जो इसे आरक्षित करता है, लेकिन इसका उपयोग नहीं किया जाता है। ओवरकॉमिट होने का मुख्य कारण फोर्किंग कार्य है। जब एक प्रक्रिया एक उपप्रकार को लॉन्च करती है, तो बच्चे की प्रक्रिया वैचारिक रूप से माता-पिता की याद की प्रतिकृति में संचालित होती है - दो प्रक्रियाओं में शुरू में एक ही सामग्री के साथ मेमोरी होती है, लेकिन यह सामग्री विचलन करेगी क्योंकि प्रक्रियाएं अपने स्वयं के स्थान में प्रत्येक में बदलाव करती हैं। इसे पूरी तरह से लागू करने के लिए, कर्नेल को माता-पिता की सभी स्मृति को कॉपी करना होगा। इससे फोर्किंग धीमी हो जाएगी, इसलिए कर्नेल कॉपी-ऑन-राइट लिखता है: शुरू में, बच्चे अपनी सारी याददाश्त माता-पिता के साथ साझा करते हैं; जब भी प्रक्रिया किसी साझा पृष्ठ पर लिखती है, तो साझाकरण को तोड़ने के लिए कर्नेल उस पृष्ठ की एक प्रति बनाता है।

अक्सर एक बच्चा कई पन्नों को अछूता छोड़ देगा। यदि कर्नेल को प्रत्येक कांटा पर माता-पिता की मेमोरी स्पेस को दोहराने के लिए पर्याप्त मेमोरी आवंटित की जाती है, तो बहुत सी मेमोरी उन आरक्षणों में बर्बाद हो जाएगी जो कभी भी बच्चे की प्रक्रियाओं का उपयोग करने के लिए नहीं हैं। इसलिए ओवरकॉमिटिंग: कर्नेल केवल उस मेमोरी का हिस्सा रखता है, जो इस अनुमान के आधार पर होता है कि बच्चे को कितने पृष्ठों की आवश्यकता होगी।

यदि कोई प्रक्रिया कुछ मेमोरी को आवंटित करने की कोशिश करती है और पर्याप्त मेमोरी नहीं बची है, तो प्रक्रिया को एक त्रुटि प्रतिक्रिया प्राप्त होती है और इससे निपटने के साथ-साथ यह फिट होता है। यदि कोई प्रक्रिया अप्रत्यक्ष रूप से साझा किए गए पृष्ठ पर लिखकर स्मृति का अनुरोध करती है, जिसे अनसेस्ड होना चाहिए, तो यह एक अलग कहानी है। इस स्थिति को एप्लिकेशन को रिपोर्ट करने का कोई तरीका नहीं है: यह मानता है कि इसके पास वहां लिखने योग्य डेटा है, और यहां तक ​​कि इसे पढ़ भी सकता है - यह सिर्फ इतना है कि लेखन में हुड के नीचे कुछ और अधिक विस्तृत ऑपरेशन शामिल है। यदि कर्नेल एक नया मेमोरी पेज प्रदान करने में असमर्थ है, तो यह सब कर सकता है अनुरोध करने की प्रक्रिया को मारना, या मेमोरी को भरने के लिए किसी अन्य प्रक्रिया को मारना।

आप इस बिंदु पर सोच सकते हैं कि अनुरोध प्रक्रिया को मारना स्पष्ट समाधान है। लेकिन व्यवहार में, यह इतना अच्छा नहीं है। यह प्रक्रिया एक महत्वपूर्ण हो सकती है जो केवल उसके एक पृष्ठ को अब एक्सेस करने की आवश्यकता होती है, जबकि अन्य, कम महत्वपूर्ण प्रक्रियाएं चल सकती हैं। तो कर्नेल में जटिल हेयूरिस्टिक्स शामिल हैं, जो यह चुनने के लिए कि किस प्रक्रिया को मारना है - ( ) प्रसिद्ध ओओएम हत्यारा


2

बस दूसरे उत्तरों से दूसरे दृष्टिकोण में जोड़ने के लिए, कई वीपीएस किसी भी सर्वर पर कई आभासी मशीनों की मेजबानी करते हैं। किसी भी एक वीएम के पास अपने स्वयं के उपयोग के लिए रैम की एक निर्दिष्ट राशि होगी। कई प्रदाता "फट रैम" की पेशकश करते हैं, जिसमें वे उस राशि से परे रैम का उपयोग कर सकते हैं जो वे नामित हैं। इसका मतलब केवल अल्पकालिक उपयोग के लिए है, और जो लोग इस समय की एक विस्तारित राशि से परे जाते हैं, उन्हें मेजबान की हत्या प्रक्रियाओं द्वारा दंडित किया जा सकता है ताकि उपयोग में रैम की मात्रा कम हो सके ताकि दूसरों को नुकसान न हो होस्ट मशीन को ओवरलोड किया जा रहा है।


-1

कुछ समय लिनक्स बाहरी आभासी स्थान लेता है। यह स्वैप विभाजन है। जब राम भरे हुए होते हैं, तो कम प्राथमिकता वाली प्रक्रिया को चलाने के लिए यह स्वैप क्षेत्र लेता है।


1
स्वैप से कोई प्रक्रिया नहीं चलती है। वर्चुअल मेमोरी को समान आकार की अलग-अलग इकाइयों में विभाजित किया जाता है, जिन्हें पेज कहा जाता है। जब भौतिक मेमोरी को मुक्त कर दिया जाता है, तो रैम से निम्न प्राथमिकता वाले पृष्ठ निकाले जाते हैं। जबकि फ़ाइल कैश में पृष्ठों में फ़ाइल सिस्टम बैकिंग है, अनाम पृष्ठों को स्वैप में संग्रहीत किया जाना चाहिए। किसी पृष्ठ की प्राथमिकता सीधे उस प्रक्रिया की प्राथमिकता से संबंधित नहीं होती है जिसका वह संबंध होता है, लेकिन इसका उपयोग कितनी बार किया जाता है। यदि कोई चल रही प्रक्रिया भौतिक स्मृति में नहीं पृष्ठ पर पहुंचने का प्रयास करती है, तो एक पृष्ठ दोष उत्पन्न होता है और प्रक्रिया को दूसरी प्रक्रिया के पक्ष में पूर्व निर्धारित किया जाता है, जबकि आवश्यक पृष्ठ को डिस्क से लिया जाता है।
थॉमस न्यूमैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.