LINUX.ORG.RU

Calloc нынче ни на что не влияет что-ли?

 ,


1

5

MWE:

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

typedef unsigned char u8;
typedef unsigned int  u32;

#define GB (1024ul * 1024ul * 1024ul)
#define TEST_SIZE (10)

int zerofy = 1;

static u8 * alloc(u32 size)
{
    u8 * res = calloc(size, 1);
    
    if (!res)
    {
        printf(" * Cannot alloc %u bytes\n", size);
        return NULL;
    }
    else
    {
        printf(" * Allocated %u bytes [%p]\n", size, res);
    }

    if (zerofy)
        memset(res, 0, size);

    return res;
}

static void rapemem(u32 zero)
{
    u32 i;
    u8 * p[TEST_SIZE];

    printf("Switching zerofy to %u\n", zero);
    zerofy = zero;

    for (i = 0; i < TEST_SIZE; i++)
        p[i] = alloc(GB);

    for (i = 0; i < TEST_SIZE; i++)
        free(p[i]);
}

int main(void)
{
    system("free -mh");
    printf("\n\n");

    rapemem(0);
    rapemem(1);
    rapemem(0);

    return 0;
}

Выхлоп:

alex@alex-thinkpad-l560:~/Разработка/C/Tests/calloc$ gcc -std=c89 poc.c 
alex@alex-thinkpad-l560:~/Разработка/C/Tests/calloc$ ./a.out 
              total        used        free      shared  buff/cache   available
Память:        7,6G        2,1G        4,2G        396M        1,2G        4,8G
Подкачка:          0B          0B          0B


Switching zerofy to 0
 * Allocated 1073741824 bytes [0x7fe248a9b010]
 * Allocated 1073741824 bytes [0x7fe208a9a010]
 * Allocated 1073741824 bytes [0x7fe1c8a99010]
 * Allocated 1073741824 bytes [0x7fe188a98010]
 * Allocated 1073741824 bytes [0x7fe148a97010]
 * Allocated 1073741824 bytes [0x7fe108a96010]
 * Allocated 1073741824 bytes [0x7fe0c8a95010]
 * Allocated 1073741824 bytes [0x7fe088a94010]
 * Allocated 1073741824 bytes [0x7fe048a93010]
 * Allocated 1073741824 bytes [0x7fe008a92010]
Switching zerofy to 1
 * Allocated 1073741824 bytes [0x7fe248a9b010]
 * Allocated 1073741824 bytes [0x7fe208a9a010]
 * Allocated 1073741824 bytes [0x7fe1c8a99010]
 * Allocated 1073741824 bytes [0x7fe188a98010]
 * Cannot alloc 1073741824 bytes
 * Cannot alloc 1073741824 bytes
 * Cannot alloc 1073741824 bytes
 * Cannot alloc 1073741824 bytes
 * Cannot alloc 1073741824 bytes
 * Cannot alloc 1073741824 bytes
Switching zerofy to 0
 * Allocated 1073741824 bytes [0x7fe248a9b010]
 * Allocated 1073741824 bytes [0x7fe208a9a010]
 * Allocated 1073741824 bytes [0x7fe1c8a99010]
 * Allocated 1073741824 bytes [0x7fe188a98010]
 * Allocated 1073741824 bytes [0x7fe143fff010]
 * Allocated 1073741824 bytes [0x7fe103ffe010]
 * Allocated 1073741824 bytes [0x7fe0c3ffd010]
 * Allocated 1073741824 bytes [0x7fe083ffc010]
 * Allocated 1073741824 bytes [0x7fe043ffb010]
 * Allocated 1073741824 bytes [0x7fe003ffa010]

WTF вообще? Теперь и calloc выделению доверять нельзя? Да здравствуют SIGSEGV без вариантов проверить выделение?

Я знаю про оптимистичное выделение, но всю жизнь эта ботва была только с malloc, calloc от этой херни был свободен так как занулял память.

★★★★★

Последнее исправление: PPP328 (всего исправлений: 1)
Ответ на: комментарий от AlexAT

грохнуть дурной на голову процесс

Это и был самый главный и нужный процесс на этом хосте. То что он заказал кучу памяти — так у него работа такая.

vodz ★★★★★
()
Ответ на: комментарий от Deleted

Что же ты не объяснил системе, что это «нужный процесс»?

Ваши предложения? Процессу нужны дырявые массивы, памяти под это без оверкоммита нет, но мы знаем, что он не пожрёт всё, если, конечно не запустят тут еще какой-нибудь монитор этого процесса на жабе, который сдохнет как не удивительно — вторым, вот только перезапустить всё равно не сможет, да и что запускать, если все данные в раскоряке по причине убийства в неожиданном месте?

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

То есть, стой, ты целенаправленно выделил памяти больше чем система может прожевать, и потом жалуешься что процесс умер от нехватки ОЗУ?

Ничего странным не кажется?

Deleted
()
Ответ на: комментарий от vodz

Замечательно. Твою проблему обсуждали где-то на второй странице. Вот почему я сейчас сижу без линукса, с телефоном, в глухомани, где сеть едва шевелится, и все же могу прочитать ман для proc(5) - а ты за все время обсуждения в этой теме этого не сделал? Это так сложно?

proc/[pid]/oom_adj (since Linux 2.6.11)

This file can be used to adjust the score used to select which process should be killed in an out-of-memory (OOM) situation. The kernel uses this value for a bit-shift operation of the process's oom_score value: valid values are in the range -16 to +15, plus the special value -17, which disables OOM-killing altogether for this process. A positive score increases the likelihood of this process being killed by the OOM-killer; a negative score decreases the likelihood.

The default value for this file is 0; a new process inherits its parent's oom_adj setting. A process must be privileged (CAP_SYS_RESOURCE) to update this file.

Since Linux 2.6.36, use of this file is deprecated in favor of /proc/[pid]/oom_score_adj.

/proc/[pid]/oom_score_adj (since Linux 2.6.36) This file can be used to adjust the badness heuristic used to select which process gets killed in out-of-memory conditions.

The badness heuristic assigns a value to each candidate task ranging from 0 (never kill) to 1000 (always kill) to determine which process is targeted. The units are roughly a proportion along that range of allowed memory the process may allocate from, based on an estimation of its current memory and swap use. For example, if a task is using all allowed memory, its badness score will be 1000. If it is using half of its allowed memory, its score will be 500.

There is an additional factor included in the badness score: root processes are given 3% extra memory over other tasks.

The amount of «allowed» memory depends on the context in which the OOM-killer was called. If it is due to the memory assigned to the allocating task's cpuset being exhausted, the allowed memory represents the set of mems assigned to that cpuset (see cpuset(7)). If it is due to a mempolicy's node(s) being exhausted, the allowed memory represents the set of mem‐ policy nodes. If it is due to a memory limit (or swap limit) being reached, the allowed memory is that configured limit. Finally, if it is due to the entire system being out of mem‐ ory, the allowed memory represents all allocatable resources.

The value of oom_score_adj is added to the badness score before it is used to determine which task to kill. Acceptable values range from -1000 (OOM_SCORE_ADJ_MIN) to +1000 (OOM_SCORE_ADJ_MAX). This allows user space to control the preference for OOM-killing, ranging from always preferring a certain task or completely disabling it from OOM killing. The lowest possible value, -1000, is equivalent to disabling OOM- killing entirely for that task, since it will always report a badness score of 0.

Consequently, it is very simple for user space to define the amount of memory to consider for each task. Setting an oom_score_adj value of +500, for example, is roughly equiva‐ lent to allowing the remainder of tasks sharing the same sys‐ tem, cpuset, mempolicy, or memory controller resources to use at least 50% more memory. A value of -500, on the other hand, would be roughly equivalent to discounting 50% of the task's allowed memory from being considered as scoring against the task.

For backward compatibility with previous kernels, /proc/[pid]/oom_adj can still be used to tune the badness score. Its value is scaled linearly with oom_score_adj.

Writing to /proc/[pid]/oom_score_adj or /proc/[pid]/oom_adj will change the other with its scaled value.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Twissel

Всё очень просто. И если уж совсем-совсем просто - «память» из себя представляет некий ассоциативный массив index->value( на самом деле block_index->block_value).

Поведение идентично поведению массива в пхп, либо где-то ещё. Ты хочешь записать данные в массив - как это будет выглядеть? Да очень просто - если за запишешь в массив байт array[0] = 1; array[10] = 2; и далее, то записей в пассиве будет всего две. Если же просто создашь массив - записей будет ноль, хотя по-факту в него писать можно.

Таким образом получается так, что пока не запишешь нужное тебе кол-во элементов(записей) в массиве/таблице их не будет. А выделяются память под эти записи будет при записи в них. А это значит, что на любом этапе памяти тебе может не хватить.

Собственно, мемсет - это просто быстрая инициализация/создание этих записей. После мемсета массива в пхп на n елементов - там уже будет памяти на n елементов. Естественно, имеются ввиду записи постоянной длинны.

Т.е. то, что хотят от мемсета - это побочное поведение. Семантика самого мемсета - просто занулить значения.

Но, произошла проблема. Если у нас пхп гарантирует результат 0 для чтения любого до этого не инициализированного елемента, то смысла в мемсете нет. Т.к. что с мемсетом, что без мемсета ты получишь ноль.

Именно так и работает calloc() и работает он правильно, но т.к. мемсета нету, то его и побочного действия( а именно инициализации всех записей) нету. В этом и заключается «проблема» автора.

rustonelove
()
Ответ на: комментарий от vodz

Процессу нужны дырявые массивы

Не нужно жрать 4КБ на элемент, лучше использовать сбалансированные деревья или хэш.

anonymous
()
Ответ на: комментарий от Deleted

Замечательно. Твою проблему обсуждали где-то на второй странице.

Её там не могли обсуждать, так как я даже не называл ОС у этой задачи.

Вот почему я сейчас сижу без линукса, с телефоном, в глухомани, где сеть едва шевелится, и все же могу прочитать ман для proc(5) - а ты за все время обсуждения в этой теме этого не сделал?

Откуда мне знать, почему вы так задрачиваетесь этим обсуждением?

Это так сложно?

Отож. Ни одной буквы полезной для прикладного программирования. Просто эталонное: доступно только с привелегиями, жутчайше linux-специфичное и ещё и не с устоявшимся алгоритмом, который представляет из себя запутанную эвристику.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Это же лолище. Использовать линукс-специфичное поведение системы не стесняется. А настроить его под свои нужды - сразу в кусты.

Deleted
()

Я конечно тему не читал, но... а calloc не может быть оптимизирован и возвращать просто zero-page? Тогда malloc+memset будет oom'ить и фейлить, а calloc - нет.

slapin ★★★★★
()
Ответ на: комментарий от Deleted

Это же лолище.

Ну хоть что-то в этом треде правда. Действительно эталонное.

Использовать линукс-специфичное поведение системы не стесняется.

Это calloc чтоли?

Использовать линукс-специфичное поведение системы не стесняется. А настроить его под свои нужды - сразу в кусты.

Кого настроить? Где в C syscall_oom*? Почему в кусты то? Оптимизировал по кушанью памяти, выдал рекомендации по swap, и нормально работает под AIX, HP UX, Linux и возможно под cygwin, но там полноценно не тестировал.

vodz ★★★★★
()
Ответ на: комментарий от PPP328

Эпично.

Конечно эпично. Как сама задача, так и ваш коммент.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Что «AIX»? Мы здесь линукс обсуждаем.

Это канал об аниме? Как пропатчить KDE под FreeBSD?

Deleted
()
Ответ на: комментарий от Twissel

Т.е. подсистема памяти ядра по сути дела может отдать сколько хошь «нулевых блоков»?

Ядро вообще не отдаёт никаких блоков. Блоки раздаются по факту записи/чтения в память. Т.е. аллокация - это просто установка флагов доступа к «аллоцируемому» диапазону индексов.

А так да, если ты читаешь элементы массива, которые по умолчанию ноль, то ничего не мешает размножить одну и ту же запись на сколько угодно много индексов. И да, в конечном итоге у тебя может быть «бесконечно» кол-во нулевой памяти. Ядро так и делает.

Пример там выше есть.

Если же ты попытаешься записать что-то, то тут уже ядро создаст нормальную запись. Типичный cow.

rustonelove
()
Ответ на: комментарий от Twissel

А причем здесь зануление блоков?

При том, что calloc не обнуляет полученную от системы память, потому что она уже гарантированно обнулена. Если бы обнулял calloc - программа упала бы в calloc, а так падение откладывается до пользовательского кода.

tailgunner ★★★★★
()
Ответ на: комментарий от vodz

Если раньше на этом адресе не было мапинга, то мапинг файла - это расширение адресного пространства. Если был - куда он исчез?

Кто «он» исчез?

Мапинг.

выплюнув в типичной манере ЛОРа — набор коротких хамских «вопросов с подковыркой»

Если «зачем» кажется тебе «хамским вопросом с подковыркой»... *shrug*

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Мапинг.

Которого не было, а тут сделали, а он исчез... Это ещё ладно, а вот если взять архитектуру, у которой для сегмента кода достаточно PROT_EXEC без PROT_READ, то подгрузка динамической библотеки вообще будет вычитать адресное пространство по вашему? А mmap(PROT_NONE)? Короче. Меняется не адресное пространство, а доступные куски адресного пространства. Последнее уточнение про куски как раз и демонстрирует, что «расширение адресного пространства» — кривое сочетание слов.

Если «зачем» кажется

Не кажется, а оно самое и есть. Не хотите парсить то длинное описание «зачем», так скипнинте и промолчите. Так нет же, тут так не принято.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Если раньше на этом адресе не было мапинга, то мапинг файла - это расширение адресного пространства. Если был - куда он исчез?
Кто «он» исчез?

Мапинг.

Которого не было,

А его не было? Ну окей. Если мапинга на этом адресе не было, а после mmap он появился - это расширение адресного пространства.

а тут сделали, а он исчез...

У тебя серьезные проблемы с пониманием текста на русском языке.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

У тебя серьезные проблемы с пониманием текста на русском языке.

Можете радостно засчитывать что тут принято - сливы или что тут сейчас модно. Никакого желания повторять всё более разжёвывая уже нет, особенно когда вместо того, чтобы попытаться понять, что пишут, тебя же и оскорбляют, вменяя непонимание.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Следующий шаг - грохнуть того, кто этот процесс запустил, не обеспечив наличие достаточного объёма памяти.

AlexAT
()
Ответ на: комментарий от AlexAT

Следующий шаг - грохнуть того, кто этот процесс запустил, не обеспечив наличие достаточного объёма памяти.

Я пошёл по более сложному пути: согласился, что кушаем как не в себя и губу надо подзакатать, изменил алгоритм и оно поехало.

vodz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.