Возможные проблемы с диском SSD SATA3

Что могло бы происходить, если процесс "уничтожается из-за низкой RAM"?

Иногда говорится, что Linux по умолчанию никогда не отклоняет просьбы о большей памяти из кода приложения - например. malloc().1 Это не на самом деле верно; значение по умолчанию использует эвристику посредством чего

Очевидный принимает на себя непосильные обязательства адресного пространства, отказаны. Используемый для типичной системы. Это гарантирует, что серьезно дикое выделение перестало работать, в то время как разрешение принимает на себя непосильные обязательства для сокращения использования подкачки.

От [linux_src]/Documentation/vm/overcommit-accounting (все кавычки от 3,11 деревьев). Точно, какое количество как "серьезно дикое выделение" не отмечено явное, таким образом, мы должны были бы пройти источник для определения деталей. Мы могли также использовать экспериментальный метод в сноске 2 (ниже), чтобы попытаться получить некоторое отражение эвристики - на основе этого, мое начальное эмпирическое наблюдение что происходит при идеальных обстоятельствах (==, система неактивна), если у Вас не будет подкачки, то Вам разрешат выделить приблизительно половину Вашей RAM, и если у Вас действительно будет подкачка, то Вы получите приблизительно половину Вашей RAM плюс вся Ваша подкачка. Это более или менее для каждого процесса (но обратите внимание, что этот предел является динамичным и подлежит изменению из-за состояния, посмотрите некоторые наблюдения в сноске 5).

Половина Вашей RAM плюс подкачка является явно значением по умолчанию для поля "CommitLimit" в /proc/meminfo. Вот то, что это означает - и обратите внимание, что это на самом деле не имеет никакого отношения к пределу, просто обсужденному (от [src]/Documentation/filesystems/proc.txt):

CommitLimit: На основе превышать возможности отношения ('vm.overcommit_ratio'), это - общий объем памяти, в настоящее время доступной, чтобы быть выделенным в системе. Этот предел только придерживается к, если строгий принимают на себя непосильные обязательства, учет включен (режим 2 в 'vm.overcommit_memory'). CommitLimit вычисляется со следующей формулой: CommitLimit = ('vm.overcommit_ratio' * Физическая RAM) + Подкачка, Например, в системе с 1G физической RAM и 7G подкачки с 'vm.overcommit_ratio' 30 это привело бы к CommitLimit 7.3G.

Ранее заключенный в кавычки превышенный возможности считавший документ указывает что значение по умолчанию vm.overcommit_ratio 50. Таким образом, если Вы sysctl vm.overcommit_memory=2, можно затем скорректировать vm.covercommit_ratio (с sysctl) и посмотрите последствия 3 режим по умолчанию, когда CommitLimit не осуществляется и только "очевидный принимает на себя непосильные обязательства адресного пространства, отказаны", когда 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: "Цель состоит в том, чтобы [уничтожить] задачу, использующую большую часть памяти для предотвращения последующих oom отказов" и косвенно № 4 ("мы хотим уничтожить минимальное количество процессов (один)).

Если Вы хотите видеть уничтожителя OOM в действии, см. сноску 5.


1 Заблуждение, от которого Gilles к счастью избавил меня, видят комментарии.


2 Вот простой бит C, который просит все больше большие блоки памяти определять, когда запрос на больше перестанет работать:

#include 
#include 
#include 

#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. Это абсолютно безопасно, поскольку процесс не использует ни одного пространства, это просит - т.е. это никогда действительно использует любую RAM.

В 3,11 x86_64 системах с системой на 4 ГБ и 6 ГБ подкачки, я перестал работать на уровне ~7400000 КБ; число колеблется, поэтому, возможно, заявите, фактор. Это по совпадению близко к CommitLimit в /proc/meminfo, но изменение этого через vm.overcommit_ratio не имеет никакого значения. В 3.6.11 32-разрядных системах ARM 448 МБ с 64 МБ подкачки, однако, я перестал работать на уровне ~230 МБ. Это интересно с тех пор в первом случае, сумма почти удваивает сумму RAM, тогда как во втором это о 1/4, что - сильно допущение объема подкачки является фактором. Это было подтверждено путем выключения подкачки в первой системе, когда пороговое значение отказа снизилось до ~1.95 ГБ, очень похожее отношение к небольшому полю ARM.

Но это действительно для каждого процесса? Это, кажется. Короткая программа ниже просит определяемый пользователем блок памяти, и если это успешно выполняется, ожидает Вас для удара возврата - этот способ, которым можно попробовать несколько одновременных экземпляров:

#include 
#include 

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

Остерегайтесь, однако, это это не строго о сумме RAM, и подкачка независимо от использования - см. сноску 5 для наблюдений об эффектах состояния системы.


3CommitLimit относится на сумму адресного пространства, допускал систему когда vm.overcommit_memory = 2. По-видимому, затем сумма, которую можно выделить, должна быть то, что минус то, что уже фиксируется, который является, по-видимому, Committed_AS поле.

Потенциально интересный эксперимент, демонстрирующий это, должен добавить #include к вершине virtlimitcheck.c (см. сноску 2), и a 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 подробно, Вы видите, что процессы чередуют свои большие и большие выделения (это легче при броске pid в вывод), пока один, очевидно, не утверждал достаточно, что другой перестал работать. Победитель затем свободен захватить все до CommitLimit минус Committed_AS.


4 Это стоит упомянуть в этой точке, если Вы уже не понимаете виртуальное обращение и подкачку по обращению, которая, что передает обязательство, возможное во-первых, то, что то, что ядро выделяет процессам пространства пользователя, не является физической памятью вообще - это - виртуальное адресное пространство. Например, если процесс резервирует 10 МБ для чего-то, это размечается как последовательность (виртуальных) адресов, но те адреса еще не соответствуют физической памяти. Когда к такому адресу получают доступ, это приводит к отсутствию страницы, и затем ядро пытается отобразить его на реальную память так, чтобы он мог сохранить действительное значение. Процессы обычно резервируют намного больше виртуального пространства, чем они на самом деле доступ, который позволяет ядру делать наиболее эффективное использование RAM. Однако физическая память является все еще конечным ресурсом и когда все это было отображено на виртуальном адресном пространстве, некоторое виртуальное адресное пространство должно быть устранено к свободному некоторая RAM.


5 Сначала предупреждение: Если Вы пробуете это vm.overcommit_memory=0, удостоверьтесь, что Вы сохраняете свою первую работу и закрываете любые важные приложения, потому что система будет заморожена в течение ~90 секунд, и некоторый процесс умрет!

Идея состоит в том, чтобы выполнить fork-бомбу, которая испытывает таймаут после 90 секунд, с ветвлениями, выделяющими место и некоторые из них пишущий большие объемы данных к RAM, все время сообщая stderr.

#include 
#include 
#include 
#include 
#include 
#include 

/* 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.

В этой среде этот вид fork-бомбы не становится очень далеким. Обратите внимание, что число в том, "говорит ветвления N", не является общим количеством процессов, это - количество процессов в продвижении цепочки/ответвления до того.

Теперь попробуйте его vm.overcommit_memory=0. При перенаправлении stderr в файл можно сделать некоторый сырой анализ позже, например:

> 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!

Только 15 процессам не удалось выделить 1 ГБ - демонстрирующий, что эвристика для overcommit_memory = 0 затронута состоянием. Сколькими процессы были там? Взгляд в конце 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 ГБ свободной RAM и 6 ГБ подкачки.

Взгляните на свои системные журналы после того, как Вы сделаете это. Необходимо видеть, что уничтожитель OOM сообщает об очках (среди других вещей); по-видимому, это касается oom_badness.

4
18.04.2014, 05:15
1 ответ

Было бы возможно отформатировать вывод с использованием GNUFIND. Предполагая, что файлы создаются самими пользователями пользователя вашей командой:

find /home/ -maxdepth 2 -type f -name '*.c' -printf '%u,%p\n'

см. Человек Найти Для более подробной информации о PrintF

Вы также можете использовать следующие

find /home/ -maxdepth 2 -type f -name '*.c' -exec bash -c 'n="${1%/*}"; n="${n##*/}"; echo "$n",$1' _ {} \;
-121--128783-

Это известная ошибка в Samsung SSDS: диски не реализуют команды TRAMP.

Однако Ubuntu (и, вероятно, большинство других дистрибутивов Linux) теперь реализуют Trim в качестве Cronjob для повышения производительности, поэтому это не имеет никакого практического интереса.

Для получения более подробной информации см. Баг ядра на этом: https://bugzilla.kernel.org/show_bug.cgi?id=72341

Причина, по которой ошибка не появилась у старых ядер, заключается в том, что они не пытаются использовать баггискую функцию привода, они таким образом Никогда не видишь ошибку. Даже более новые ядра (4.0 и вперед) знают, что приводы имеют эту ошибку, поэтому ошибка не будет отображаться для привода в будущем.

3
27.01.2020, 20:58

Теги

Похожие вопросы