LINUX.ORG.RU

Правильное использование realloc

 ,


0

5

Статические анализаторы любят ругаться на такую конструкцию:

ptr=realloc(ptr, size);

Если память не выделится, то в ptr запишется 0, а старое значение ptr будет потеряно, ужас-ужас.
Ну и что? Если память не выделилась, то значит, все очень плохо и программе нет смысла работать.
Она грохнется при попытке разыменовать ptr.

★★

Ответ на: комментарий от Stanson

А слабо не использовать баззворд «контейнеры» и говорить на нормальном человеческом языке?

Ты не знаешь что такое контейнер? Так бы и сказал:
https://en.wikipedia.org/wiki/Container_(abstract_data_type)

In computer science, a container is a class, a data structure,[1][2] or an abstract data type (ADT) whose instances are collections of other objects. In other words, they store objects in an organized way that follows specific access rules.

Проблемы вызывает ужор памяти всякими сраными «контейнерами».

В каком месте происходит «ужор»? Покажи пальцем, желательно с практическими примерами и кодом соответствующим. Чтобы было: «вот программа жрет 100мб, я оптимизировал, стала жрать 50мб».

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

когда к 100МБ надо добавить пару килобайтных объектов

А потом ещё, а потом ещё два раза, и ещё. Ой, и ещё. Ах да, совсем забыл, и ещё.

Удвоение памяти позволяет контейнеру расти за O(N) вместо O(N^2) при последовательном добавлении объектов.

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

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

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

Не придёт :-) Женька занят очень нужным его фирме делом - прокачкой скила в общении с неадекватами :-)

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

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

Какие мы умные, аж противно.

А ты вообще в курсе, что у всяких там MMU есть гранулярность, которую называют «размер страницы»? Опиши мне, как ты обойдёшься без копирования на следующем примере:

  • сто раз malloc(1024)
  • realloc(<первый выделенный фрагмент>, 2048)
intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

Опиши мне, как ты обойдёшься без копирования на следующем примере:

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

Stanson ★★★★★
()

какой годный вброс

В зависимости от задачи можно применять различные варианты

Когда пофиг на небольшой оверхед, но нужно быть более уверенным в результате realloc(), я бы наваял какой-нибудь велосипед типа такого

void *realloc_for_sure(void *ptr, size_t newsize, size_t oldsize) {
    if (newsize < oldisze) return realloc(ptr, newsize);
    void *check = calloc(newsize - oldize, sizeof(char));
    if (check == NULL) return NULL;
    free(check);
    return = realloc(ptr, newsize);
}
Но вообще, не нужно лениться проверять NULL. От пары лишних строчек кода читаемость не особо упадет если человек хоть сколько-нибудь работал с ЯП.

ВНЕЗАПНЫЕ выстрелы в ногу в продакше это очень весело, иногда приводят к выходам на работу в воскресенье в 8 утра.

reprimand ★★★★★
()

Ах да, насчёт споров про удвоение использования памяти.

Опять таки, почему-то народ забил болт упомянуть, что всё зависит от задачи. Если в буффер постоянно вбрасываются данные, то нет смысла добавлять realloc()-ом кусочки одинакового размера.

Другое дело, что разраб ПО может продумать как часто данных приходит в таком-то количестве и сколько в таком-то, и в результате, например (для сферического софта в вакууме):

1) До 50 мегабайт увеличиваем объем буфера умножением на 2.
2) До 100 мегабайт добавляем по 10 мегабайт
3) Выше 100 мегабайт добавляем по 1 мегабайту

СЛОЖНО-ТО КАК! Подуамать только - разраб может думать головой о сценариях использования его проделок! Ого!

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

Знали бы об этом [censored], разрабатывающие браузеры, охфисы и прочую дрянь, жрущую память похлеще чОрных дыр...

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

подозреваю что там не только в этом проблема...

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

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

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

Это же бред, нет?

  • Чем это выгодно отличается от #define realloc_for_sure(ptr, newsize, oldsize) realloc(ptr, newsize)?
  • Почему calloc?
  • Почему sizeof(char)?
  • Почему return =?
doushiyou
()
Ответ на: комментарий от doushiyou

Почему return =?

Опечатка, там не должно быть знака «=».

Почему calloc?

Потому что calloc еще и инициализирует память. Это означает, что она 100% будет доступна, в отличие от.

Почему calloc?

мы проверяем можем ли мы выделить память в объеме (newsize - oldsize). Т.е. насколько больше памяти нам нужно - настолько и пытаемся выделить calloc()-ом.

Почему sizeof(char)?

ОМГ. А сколько ты хотел совать calloc()-у?

Чем это выгодно отличается от #define realloc_for_sure(ptr, newsize, oldsize) realloc(ptr, newsize)?

Тем, что увеличивает вероятность доступности новой памяти.

Я уже сказал, что ТС не поставил задачу, посему мой ответ был узкоспециализированный, обрати на слово «если» в моём посте.

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

Потому что calloc еще и инициализирует память. Это означает, что она 100% будет доступна, в отличие от.

http://stackoverflow.com/a/2688522

https://linux.die.net/man/3/malloc

Normally, malloc() allocates memory from the heap, and adjusts the size of the heap as required, using sbrk(2). When allocating blocks of memory larger than MMAP_THRESHOLD bytes, the glibc malloc() implementation allocates the memory as a private anonymous mapping using mmap(2).

https://linux.die.net/man/2/mmap

MAP_ANONYMOUS
The mapping is not backed by any file; its contents are initialized to zero. The fd and offset arguments are ignored; however, some implementations require fd to be -1 if MAP_ANONYMOUS (or MAP_ANON) is specified, and portable applications should ensure this. The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is only supported on Linux since kernel 2.4.

Т.е. для больших объемов calloc реализован так же, как и malloc.

ОМГ. А сколько ты хотел совать calloc()-у?

1 же.

Тем, что увеличивает вероятность доступности новой памяти.

OOM killer прибивает не того, кому не хватило памяти (это может быть какой-то важный системный демон), а того, у кого наибольший oom_badness. См. https://linux-mm.org/OOM_Killer.

Глупость какая-то, в общем.

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

Т.е. для больших объемов calloc реализован так же, как и malloc.

Может наоборот? Для больших объемов malloc() ведет себя так же как и calloc()?
Окей, а что с малым объемом будем делать? Проигнорируем к чертям собачьим?

1 же.

1 == sizeof(char)

OOM killer прибивает не того, кому не хватило памяти (это может быть какой-то важный системный демон), а того, у кого наибольший oom_badness. См. https://linux-mm.org/OOM_Killer.

Ну ок.

Глупость какая-то, в общем.

Смотря под каким углом посмотреть.

Я еще раз акцентирую внимание, что без постановки задачи дискутировать не о чем.

З.Ы. Спасибо за ссылку, интересно было почитать.

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

Окей, а что с малым объемом будем делать? Проигнорируем к чертям собачьим?

В свете вот этого:

OOM killer прибивает не того, кому не хватило памяти (это может быть какой-то важный системный демон), а того, у кого наибольший oom_badness. См. https://linux-mm.org/OOM_Killer.

вся эта функция вообще не имеет смысла, нет?

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

наибольший oom_badness

вся эта функция вообще не имеет смысла, нет?

Я не нашел логической связи. Как определяется oom_badness я уже посмотрел. Угадать, будет ли наше ПО убито или нет сложно.

Или я чего-то не понимаю? Объясни, пожалуйста.

Мне кажется, ты хочешь сказать, что если мы не можем получить больше памяти, то именно наш процесс будет убит, так? И потому функция доп. проверки не имеет смысла?

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

Мне сейчас лень думать.

На самом деле мне очень всё это интересно. Если будет время - отпишись, пожалуйста.

Просто сама идея мне показалась какой-то уж очень бредовой.

а ты посмотри в котором часу я этот бред писал :D

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

а ядро просто убивает прогу SIGKILL'ом, бггг

переключаем режим malloc и никто ничего не убивает.

если ошибка МОЖЕТ возникнуть она ДОЛЖНА быть обработана, кто с этим не согласен - унылый говнокодер.

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