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)

Ответ на: комментарий от post-factum

calloc time: 4.636 us

Читерит. Там 4кб, а не твои 512метров.

calloc time: 0.048 us

Привет выпил каллока.

Мерильщик от бога. Твоя разница никак не связана с тем, что наплёл пациент выше.

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

Не бывает "собственного предварительно зануленного пула". Как-то в аналогичном флудотреде кто-то приводил примеры кода memset и calloc.

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

Для выделения свежих 1 Гб памяти malloc() и calloc() используют mmap() с MAP_ANONYMOUS, что гарантирует занулённость полученных данных. Но calloc() из eglibc всё равно вызывает memset(), заставляя ядро предоставить реальную память процессу. :(

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

Для выделения свежих 1 Гб памяти malloc() и calloc() используют mmap() с MAP_ANONYMOUS, что гарантирует занулённость полученных данных.

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

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

Будут, но calloc() всё равно быстрее.

[~]$ ./test                              
calloc time: 10597.543 us
malloc+memset time: 206635.108 us
post-factum ★★★★★
()
Ответ на: комментарий от TrueTsarC

Вот тебе принудительно memset до вызова free после calloc():

[~]$ ./test
calloc time: 10435.893 us
malloc+memset time: 196440.304 us

Никакого читерства. Память выделяет? Что ещё надо.

post-factum ★★★★★
()
Ответ на: комментарий от Eddy_Em

Если «нужно выделить немного», на первом свежем выделении malloc тоже вернёт занулённую память, просто из-за того, что ядро всегда отдаёт забитые нулями страницы, но память, полученную через sbrk, malloc после free обратно не отдаёт и переиспользует, вот такой переиспользованный кусок уже может быть с «мусором». Естественно, это всё специфично для линукса и glibc

Gvidon ★★★★
()

facepalm

сложно man 3 malloc открыть, или ты с маздая пишешь и в гугле забанен?

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

ещё один идиот.

The malloc() and calloc() functions return a pointer to the allocated memory, which is suit‐ ably aligned for any built-in type. On error, these functions return NULL. NULL may also be returned by a successful call to malloc() with a size of zero, or by a successful call to cal‐ loc() with nmemb or size equal to zero.

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

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

не уподобляйся, это системозависимо.

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

Твой макрос сделает тебе весело

твой тоже говно из 80х, когда компилятор не умел inline.

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

По крайней мере в BSD так.

ну по стандарту это системозависимо. В glibc я уже выше процитировал.

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

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

реально, если испортишь heap. А с твоим говностилем это вопрос времени.

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

Даже если софт очень критичен и от него зависит будущее человечества - все равно такие проверки смысла большого не несут

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

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

В последних версиях glibc brk не исползуется. Все выделяется через memmap - если большой блок то возвращается прамо то что отдал memmap. Если блоки маленькие то выделяется большой сегмент через memmap и уже внутри него организовывается куча. Если сегмент закончился - выделяется новый через memmap, если в сегменте нет занятых блоков - он освобождается.

BRK очень не практичен, при организации кучи через brk практически не реально возвращать память системе (из-за фрагментации и линейности сегманда данных).

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

значит, calloc делает программу более предсказуемой, а это юниксвейно :)

ещё одним говнокодером стало больше.

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

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

Эдди, почему-бы тебе просто не сделать серилизацию в файл?

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

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

ну и нахрена ты купил себе компьютер с 2Гб на борту?

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

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

И что? Я получу сигфолт - мне придет письмо, сервис перезапустится. Я зайду на сервер подниму кору и увижу что был возврат NULL из malloc. Посмотрю статистику - увижу что процесс перед крашем занимал потреблял много VMEM и начну разбиряться почему закончилась память. Меня это вполне устраивает, по крайней мере для меня это в разы лутче чем если бы был подобный макрос и мой сервис вместо краша тупо ушол в вечный for с ожиданиеме памяти которую никто не вернет.

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

Я зайду на сервер подниму кору и увижу что был возврат NULL из malloc.

это если malloc, а не calloc/malloc+memset.

в вечный for

этот макрос — тупое говно.

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

А причем тут 2G на борту ?

ну ты говоришь «мало вероятно, что процессы занимают 2Г», а зачем тебе столько памяти в десктопе тогда? У тебя там 100500 процессов?

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

это если malloc, а не calloc/malloc+memset.

А чем будет отличатся ситуация с calloc/malloc+memset ? от malloc +read/write ?

этот макрос — тупое говно.

Во первых тред какраз про этот макрос, во вторых вам бы не помешало улутшить свою культуру общения.

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

ну ты говоришь «мало вероятно, что процессы занимают 2Г», а зачем тебе столько памяти в десктопе тогда? У тебя там 100500 процессов?

Я говорил что маловероятно что один 32битный процесс занимает 2Г. Но это никак не связано с ко-вом оперативной памяти в системе. 2Г это проектный лимит (иногда 3Г) для любого 32 битного процесса (на IA-32). И поэтому разработчика как правило учитывают эту особенность и реализуют программы так чтобы они потребляли значительно меньше памяти в 32 битной среде - иначе очень высока вероятность падения процесса. Но свои 2Г процесс может получить как на системе с 512М ОЗУ так и на системе с 64Г. А вот больше он не сможет получить никак будь там хоть 1Т RAM.

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

А чем будет отличатся ситуация с calloc/malloc+memset ? от malloc +read/write ?

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

Каноничный пример: браузер. Браузер не в курсе, на какой сайт ты пойдёшь, и сколько памяти отожрёт какой-нить JavaScript на твоём сайте. Обычно такие скрипты жрут копейки, но нетрудно наговнокодить любое число гигабайт, в т.ч. и неограничено много. И с этим ничего не поделать, т.к. разработчики браузера не могут повлиять на разработчиков говноскриптов.

Не, можно выделять небольшими кусками, но это намного дольше. Проще доверить эту работу процессору и ядру, как только процесс запросит страничку, которая в виртуальной памяти, сработает исключение, и ядро ОС вставит страничку из физической. Это очевидно быстрее, чем если ты выделяешь сразу МНОГО страниц, и значительно быстрее, если выделением памяти будет заниматься не CPU, а твой код.

Во первых тред какраз про этот макрос, во вторых вам бы не помешало улутшить свою культуру общения.

хорошо. Макрос, это отсутствие культуры. И сильное осложнение для того, кто будет этот код поддерживать. Попробуй, и сам начнёшь изливать тонны НЕНАВИСТИ на вот таких вот ***, как ТС.

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

Но свои 2Г процесс может получить как на системе с 512М

в случае calloc/malloc+memset — не может.

Я говорил что маловероятно что один 32битный процесс занимает 2Г.

на самом деле, от процесса совершенно не зависит, сколько памяти ему надо. Если скормить sed строку в 2.5Г, она затребует 4Гб, и если получит, пожрёт из неё 3Гб как минимум. Какими строками будут кормить sed, от самой sed никак не зависит. Тут на ЛОРе очень многие любят код типа такого:

for i in `seq 1 100000000`; do…
писать
for ((i=1; i<=100000000; i++)); do…
никто не желает.

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

Слишком медленно. mmap на файл, конечно, можно сделать, чтобы ведро само память выделяло, но представь себе — как считать Фурье от картинки в несколько десятков (а то и сотен) мегабайт?

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

Слишком медленно.

facepalm

делай серилизацию каждые N минут. Тогда потери составят около N/2 минут работы.

Учти, при нехватке памяти, OOM может и твою программу грохнуть, а не ФФ. Или может убить Xorg, а Xorg убьёт термина и твой код. Или вообще всё зависнит нахрен.

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

Ну да, посмотреть, во что раскрывается макрос MORECORE, — это определённо за пределами человеческих возможностей

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

Ну как ты это будешь делать, если нужна вся память?

Кстати, я до сих пор не придумал шустрого алгоритма аппроксимации данных при недеструктивных считываниях (т.е. ставим, скажем, экспозицию на полчаса и каждые 20-30 секунд делаем недеструктивное считывание, аппроксимация позволяет раз в 10 шумы снизить!): сразу загнать в память сотню-другую изображений — маловероятно. А cfitsio, собака, имеет ограничение на максимум 32 файла что ли (а патчить ломает), поэтому одновременно их открыть не так просто (чтобы построчно считывать). Промежуточный вариант у меня был: создать 1024 директории, в каждой по 1024 файла и заносить туда интенсивности. Затем каждый файл обрабатывать и вычислять реальную интенсивность + шум. Этот велосипед у меня считался около недели! Самая жопа была — дисковые операции.

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

Ну как ты это будешь делать, если нужна вся память?

записывать на hdd. Не вижу проблемы.

Самая жопа была — дисковые операции.

а тож. Делай так:

1. вот как сейчас считаешь, так и считай

2. каждые N минут останавливай расчёт, пиши ВСЁ на HDD, потом продолжай.

Для надёжности надо сначала писать в файл1, потом в файл2, опять в файл1 и так далее, на случай, если сбой будет в момент записи.

Ещё sync делай после каждой записи.

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

зависит от реализации. Впрочем, как и реакция calloc(3).

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

Да там действительно есть brk. Но на сколько я понял он используется только для main_arean, остальные сегменты они получают через new_heap который реализован через mmap.

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

От идиота слышу.

ну хоть от идиота, да man page ты прослушал. Там, кстати, ещё много других буквочек, вдруг пригодится?

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

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

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

Никогда не вернет, раньше oom killer сработает.

$ gcc malloc.c -O2 -o malloc -std=c99 -m32
$ ./malloc 
4075: oops! address space exhausted
(nil)
$ cat malloc.c 
#include <stdio.h>
#include <stdlib.h>

#define NCHUNK (128 * 1024)
#define CHUNKSIZE (1024 * 1024)

int main()
{
	void *chunks[NCHUNK];
	size_t allocated;
	for (allocated = 0; allocated < NCHUNK; allocated++) {
		chunks[allocated] = malloc(CHUNKSIZE);
		if (!chunks[allocated]) {
			printf("%zd: oops! address space exhausted\n", allocated);
			break;
		}
	}

	for (size_t i = 0; i < allocated/2; i++) {
		free(chunks[i * 2]);
	}

	void *p = malloc(CHUNKSIZE * 2);
	printf("%p\n", p);
}

Это царь тут всех так подпортил, да? Я просто не следил что в прошлом году на лоре происходило, похоже пропустил самое вкусное.

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

Но на сколько я понял он используется только для main_arean

Это именно то, что происходит, каждый раз когда ты вызываешь malloc с размером, меньшим mmap threshold, а это подавляющее большинство вызовов malloc.

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

Чтото я в этом не уверен, но спорить не буду. Когда я последний раз разбирался (гдето пол года - год назад) я явно видел что там есть несколько «арен» для размещения малых объектов (до 1К) и оснавная масса этих арен получалась через mmap, а основная (main) - это хвост даты (brk). Правда я разбирался с glibc из довольно старой системы (CentOS 5) - может в текущей версии чтото по другому, а может я чтото напутал :).

И судя по коду __libc_free

void __libc_free (void *mem)
{
 ....
 p = mem2chunk (mem);
  if (chunk_is_mmapped (p)) /* release mmapped memory. */
    { // Когда использовался mmap для выделения блока
      ...
      munmap_chunk (p);
      return;
    }
                      
  ar_ptr = arena_for_chunk (p); // Получаем арену в которой был выделен малый блок
  _int_free (ar_ptr, p, 0);
}
арен может быть несколь для общей кучи ...

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

Вот тебе принудительно memset до вызова free после calloc():

Он не вызывается. Зачем ты несёшь херню? Почему все ламерки такие глупые?

Все ваши проблемы от того, что вы не представляете порядка величин и вообще нихрена не знаете о матчасти. Если ты не понимаешь, что твои цифры говно - считай во вменяемых единицах, а в неведомой херне.

(10435.893*10^−6)=0.010435893 - ты сможешь посчитать это в GB/s? А потом подумай, какой жопой оно с такой скоростью заполнит память. Уж это осиль, я уж не говорю об чтении кода реализаций.

Давай я напишу за тебя не говно:

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdint.h>
#include <omp.h>

enum {KB = 1024, MB = KB * 1024, GB = MB * 1024, TB = GB * 1024ul};

#define Mbench_tpt(name, calls, data_len, call) ({\
  uint64_t i = calls;\
  double start = omp_get_wtime();\
  do {\
    call;\
  } while(--i);\
  double time = omp_get_wtime() - start;\
  fprintf(stderr, "%s: (%lu)%luKB: total %luGB: %fGB/s\n", name, (uint64_t)calls, data_len/KB, ((uint64_t)data_len * calls)/GB, ((double)((uint64_t)data_len * calls)/time)/GB);\
})

int main(void) {
  uint64_t data_len = 512 * MB;

  Mbench_tpt("calloc+memset", 20, data_len, ({
    free(memset(calloc(1, data_len), 0, data_len));
  }));

  Mbench_tpt("malloc+memset", 20, data_len, ({
    free(memset(malloc(data_len), 0, data_len));
  }));

  Mbench_tpt("calloc", 20, data_len, ({
    void * volatile p = calloc(1, data_len);//авось мозгов хватит
  }));
}
calloc+memset: (20)524288KB: total 10GB: 4.319582GB/s
malloc+memset: (20)524288KB: total 10GB: 4.335490GB/s
calloc: (20)524288KB: total 10GB: 377122.023040GB/s

Никакого читерства. Память выделяет? Что ещё надо.

Понимаешь в чем штука, если ты чего-то не понимаешь - это не значит, что этого нет. Ты можешь прийти и побалаболить в тему, но зачем? Надо думать, перед тем, как нести херню, понимаешь?

Тебе сказали - там 4к, а не 512метров. В чем твоя проблема? Тебе рассказать почему?

TrueTsarC
()
Ответ на: комментарий от post-factum

Ты даже не разобрался в своих числах!

В чем конкретно я не разобрался? Ты же мне сможешь ответить, либо ты просто так это вякнул?

А давайте превратим и этот тред в эпичный?

По существу есть что сказать? Первый раз же попытался ответить, но обосрался. Больше не хочется? Либо в чем проблема? Почему же тебе нечего ответить?

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