LINUX.ORG.RU

нубский вопрос по malloc

 ,


1

4

когда malloc возвращает 0? в общем набыдлокодил макрос, чтобы не проверять возвращаемое из malloc

#define GET_MEM(p,s) for(p=NULL;!(p=calloc(1,s));perror("calloc"))
как думаете, не нужно? и чем чревато?

★★★

Последнее исправление: IvanR (всего исправлений: 1)

чем чревато?

Вечный цикл, т.е. системе памяти не хватает, а тут её ещё добивают забирая процессорное время.

xaizek ★★★★★
()

ну хоть послипай между аллоками

А вообще это полная херня, конечно

thesame ★★★★
()

когда malloc возвращает 0?

Если просишь больше, чем в лимитах sysfs стоит. Если же этих лимитов нет, то никогда.

В теме срочно нужен Царь.

Eddy_Em ☆☆☆☆☆
()

не проверять возвращаемое из malloc
calloc

Царя на тебя не хватает! А ничего, что malloc выделяет виртуальную память, а calloc ее инициализирует? Т.е. если ты на 2ГБ оперативы попросил 4ГБ, malloc тебе ее даст, но использовать всю ты не сможешь (в принципе, быдлорукожопые индусокодеры так и делают — смотри на тормозиллу и хромоногого). А calloc сразу же отвалится, как только memset попытается выйти за пределы доступного.

Eddy_Em ☆☆☆☆☆
()
#define GET_MEM(...) do { ... } while ( ... )

Твой макрос сделает тебе весело, если ты забудешь точку с запятой после GET_MEM, а мой сразу выдаст ошибку в нужной строчке.

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

ну тогда вот так:

do{for(...);}while(0)
IvanR ★★★
() автор топика

вносите!

anonymous
()

когда malloc возвращает 0?

Когда не может выделить запрашиваемое количество памяти. Конкретные причины могут быть совершенно разными и сильно зависят от системы и окружения

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

Тебя раньше OOM Killer прибъёт. А вообще _на линуксе_ получить 0 от malloc практически нереально. Разве что ты работаешь на системе без MMU. Память тебе выделят всегда, но при попытке в неё написать софтину убьют.

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

_на линуксе_ получить 0 от malloc практически нереально

malloc(-1)

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

Тебя раньше OOM Killer прибъёт. А вообще _на линуксе_ получить 0 от malloc практически нереально. Разве что ты работаешь на системе без MMU. Память тебе выделят всегда, но при попытке в неё написать софтину убьют.

Реально. На 32х разрядной системе, даже когда свободная память есть, достаточно сфрагментировать кучу.

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

Что тебе вернут указатель, но когда начнут использоваться конкретные страницы памяти придёт злой и страшный OOMKiller и пристрелит.

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

Не на что указатель возвращать, виртуальное адресное пространство исчерпано. Свободная память есть, но нет свободного блока нужной длины.

AptGet ★★★
()

Чето у меня с вашим дефайном «Hello World» не работает

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

#define GET_MEM(p,s) for(p=NULL;!(p=calloc(1,s));perror("calloc"))

int main()
{
        void *m;

        GET_MEM(m, 100)
        printf("HELLO WORLD!\n");

        return 0;
}

По сабжу - от таких костылей больше вреда чем пользы, иногда гораздо лутше если программ просто упадет в кору чем уйдет в себя и будет непонятно что делать. + получить 0 после маллока практически не реально + если маллок таки вернул 0 то скорее всего с текущий процесс уже сожрал все до чего мог дотянутся, и высока вероятность что сервер в жутком свопе и плохо реагирует на внешние раздрожители - как результат проще/лутше чтоб текущий процесс просто закрашелся чем продолжал насиловать систему.

Даже если софт очень критичен и от него зависит будущее человечества - все равно такие проверки смысла большого не несут, в таких случаях нужно применять атказоустойчевые алгоритмы/системы при которых краш приложения (по OOM, по причине выхода из строя железа, просто по килу кривого админа, из-за бага в коде и тд) не должен приводить к апокалипсису ... .

PS. Если уже и делать проверки то я бы сделал чтото вроде такого:

#define GET_MEM(p,s) if(NULL == (p=malloc(1,s)));{perror("malloc panic");abort();}

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

Ну, смотря что ты хочешь сделать. Скажем, чтобы выделить память для структуры или массива, я вызываю calloc (чтобы не инициализировать потом некоторые "умолчательные" поля нулями). А если для строки или данных, которые нулями инициализировать не нужно, то можно и malloc. Я редко жру память гигабайтами, поэтому пофиг. Ну, а когда мне реально нужно было пару гигабайт отожрать, я вызывал calloc, чтобы быть уверенным, что через полдня расчетов моя программулинка не упадет из-за того, что какая-то хромоногая скотина сожрала все остатки памяти!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Dark_SavanT

А вообще _на линуксе_ получить 0 от malloc практически нереально.

Да откуда вы лезете?! 32-битный процесс может сожрать свои 4 гига очень легко и быстро. А если он запущен на 64-битном ядре с кучей оперативки, то вся система к тому моменту может себя чувствовать вполне хорошо. Про лимиты выше сказали, хотя, конечно, простые смертные их никогда не ставят.

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

Да откуда вы лезете?! 32-битный процесс может сожрать свои 4 гига очень легко и быстро. А если он запущен на 64-битном ядре с кучей оперативки, то вся система к тому моменту может себя чувствовать вполне хорошо. Про лимиты выше сказали, хотя, конечно, простые смертные их никогда не ставят.

Я вот както особо не встречал чтобы 32 битный процесс очень быстро выжирал свои 4 гига (хотя реально у него их всего 2 в дефолтной конфигурации т.к. младшие 2 это кернелспейс), и даже не встречалось чтобы вот так сразу брал и сжирал 2гига. Обычно они ведут себя по скромнее. Отсюда вывод - получить 0 из малока маловероятно, а если и получиш то лутше сразу падать/завершаться чем чтото пытаться переполучить (за исключением редких спец случаев).

Повторю - ситуация когда 32битное приложение потребляет 2Г не нормальна, и маловероятна.

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

Love очень любит (гыгы) проверять маллок на NULL

unt1tled ★★★★
()

я починил

#define GET_MEM(p,s) for(p=NULL;!(p=calloc(1,s));perror("calloc"),abort())
Deleted
()

Какбе в треде не хватает капитана, который сообщит, что реализаций malloc over 9000. Ну ляликсятникам это же не надо знать, у них glibc повсюду

anonymous
()

как думаете, не нужно?

Макрос не нужен, проверять результат malloc нужно.

Vovka-Korovka ★★★★★
()
Ответ на: комментарий от AptGet

Если так, то согласен, но уж больно специфическая ситуация, тут уже свой аллокатор писать надо.

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

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

И да, я результат malloc всегда на NULL проверяю. Не из принципа, привычка таксказать, стараться все возвращаемые указатели на NULL проверять.

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

Я вот както особо не встречал чтобы 32 битный процесс очень быстро выжирал свои 4 гига (хотя реально у него их всего 2 в дефолтной конфигурации т.к. младшие 2 это кернелспейс),

Самая распространённая конфигурация раньше была 3 + 1, а позже с EMT64 окло 3.4 на 0.6. malloc() реально возвращает 0 как только заканчивается адресное пр-во для sbrk() или mmap().

Отсюда вывод - получить 0 из малока маловероятно

Чушь же. Текучие долгоживущие сервисы на 32битных ядрах всегда доходят до такого состояния, не обязательно выжирать всё сразу.

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

А calloc сразу же отвалится, как только memset попытается выйти за пределы доступного.

Я думал, calloc() выделяет память из собственного предварительно занулённого пула или просит ядро смаппить ему новых страничек (которые зануляются самим ядром перед тем, как быть отданными процессу).

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

А вообще _на линуксе_ получить 0 от malloc практически нереально

Да запросто. prlimit с минимальными значениями и calloc сразу же вернет NULL.

Deleted
()

Как вам уже написали, черевато зацикливанием программы.

Совсем не обязательно, чтобы было 32-бит и фрагментированная куча, может быть ″echo 2 > /proc/sys/vm/overcommit_memory″, может быть не glibc, может быть вобще не Линукс, и там calloc будет стабильно возвращать NULL. Если вы расчитываете, что ваша программа когда-нибудь станет полезной и будет работать не только на вашем localhost'е, то не нужно такое поведение.

Ведь ещё бывает, что stderr перенаправляют в файл, то есть этот цикл бесконечного ожидания памяти не только будет жрать процессор, но и место на ФС.

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

На всякий случай:

[~]$ cat test.c
#define _DEFAULT_SOURCE

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

#define ALLOC_SIZE      (512 * 1024 * 1024)     // 512 MiB
#define LOOPS           20

int main(int argc, char** argv)
{
        (void)argc;
        (void)argv;
        void* p;
        time_t time_diff;
        double time_diff_avg;
        double time_diff_avg_us;
        struct timespec time_start, time_end;

        time_diff = 0;
        for (unsigned int i = 0; i < LOOPS; i++)
        {
                clock_gettime(CLOCK_MONOTONIC, &time_start);
                p = malloc(ALLOC_SIZE);
                memset(p, 0, ALLOC_SIZE);
                clock_gettime(CLOCK_MONOTONIC, &time_end);
                free(p);
                time_diff +=
                        (time_end.tv_sec * 1000000000ULL + time_end.tv_nsec) -
                        (time_start.tv_sec * 1000000000ULL + time_start.tv_nsec);
        }

        time_diff_avg = (double)time_diff / (double)LOOPS;
        time_diff_avg_us = time_diff_avg / 1E3;

        printf("malloc+memset time: %1.3lf us\n", time_diff_avg_us);

        time_diff = 0;
        for (unsigned int i = 0; i < LOOPS; i++)
        {
                clock_gettime(CLOCK_MONOTONIC, &time_start);
                p = calloc(1, ALLOC_SIZE);
                clock_gettime(CLOCK_MONOTONIC, &time_end);
                free(p);
                time_diff +=
                        (time_end.tv_sec * 1000000000ULL + time_end.tv_nsec) -
                        (time_start.tv_sec * 1000000000ULL + time_start.tv_nsec);
        }

        time_diff_avg = (double)time_diff / (double)LOOPS;
        time_diff_avg_us = time_diff_avg / 1E3;

        printf("calloc time: %1.3lf us\n", time_diff_avg_us);

        exit(EX_OK);
}
[~]$ gcc -O0 -std=c99 -lrt -o test test.c
[~]$ ./test                              
malloc+memset time: 240563.006 us
calloc time: 4.636 us
[~]$ gcc -O3 -std=c99 -lrt -o test test.c
[~]$ ./test                              
malloc+memset time: 242519.131 us
calloc time: 0.048 us
post-factum ★★★★★
()
Ответ на: комментарий от mashina

может у вас получить 0 из малоки и в порядке вещей. Но в моей практике я такого вообще не помню чтобы было. Возможно вы путаете понятия маловероятно и невозможно ?

zaz ★★★★
()
Последнее исправление: zaz (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.