Calloc дать память


Содержание

SBP-Program

Работа с памятью в C

Для работы с памятью в C используют библиотечные функции: free(), malloc(), calloc(), realloc().

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

_msize

Функция _msize возвращает размер область памяти, выделенной из кучи:

аргумент — указатель на блок памяти. Функция _msize возврашает размер памяти в байтах. size_t — это unsigned integer.

malloc

Функция malloc выделяет область памяти из «кучи» (т.е. свободной области памяти):

аргумент определяет количество байтов, которое надо выделить из памяти. Функция malloc возвращает void указатель на выделенную область памяти, его можно привести к нужному типу. Если свободной для выделения памяти меньше, чем затребовоно в size_t, то функция malloc вернет NULL.

Пример работы с функцией malloc:

здесь выделено место в памяти для массива, состоящего из двух элементов типа int. Если выделение памяти пошло успешно, то освобождаем эту область памяти с помощью функции free.

calloc

Функция calloc выделяет область памяти и размещает в ней массив, инициализированный нулями:

первый аргумент количество элементов, а второй — размер в байтах одного элемента. Произведение значений аргуменов и даст величину области памяти, запрошенной для выделения. Функция calloc возвращает void указатель на выделенную область памяти, его можно привести к нужному типу. Если свободной для выделения памяти меньше, чем затребовоно, то функция calloc вернет NULL.

Пример работы с функцией calloc:

в примере выделяется память для массива типа int, содержащего два элемента. Эти элементы инициализированны нулями. Если выделение памяти пошло успешно, то освобождаем эту область памяти с помощью функции free.

realloc

Функция realloc меняет размер предварительно выделенной области памяти:

первый аргумент — это указатель на область памяти, размер которой нужно изменить, второй аргумент определяет новый размер области памяти. Если этот размер равен нулю, а первый аргумент указывает на имеющуюся область памяти, то функция realloc вернет NULL, а исходный блок памяти, на который указывает первый аргумент, будет освобожден. Если свободной для выделения памяти меньше, чем затребовоно, то функция realloc вернет NULL, а исходный блок памяти, на который указывает первый аргумент, сохраниться и останется без изменений. Функция realloc возвращает void указатель на выделенную область памяти, его можно привести к нужному типу.

Пример работы с функцией realloc:

В примере с помомощью функции malloc выделяем область памяти, далее с помощью функции realloc увеличиваем эту память.

Определить, сколько памяти выделил malloc под массив

Подскажите, пожалуйста, можно ли узнать, сколько памяти выделено под массив, на который ссылается указатель, к примеру int *array ?

Суть проблемы в том, что есть файл, в котором на первой строке записано кол-во строк матрицы, на второй строке файла — кол-во столбцов матрицы, далее записана сама матрица (строка матрицы в отдельной строке файла). Все это дело считывается в одномерный массив структур (в структуре хранится позиция элемента в двумерной матрице и само значение элемента)

После считывания первых двух строк из файла, создаю указатель Matrix *values на массив структур и маллочу нужное кол-во памяти.

И есть заголовок функции, которую надо реализовать

В эту функцию передается сам массив структур, строка и столбец элемента, который надо получить. В нее НЕ передается ни кол-во элементов, ни кол-во строк и столбцов в исходной двумерной матрице.
Оперируя этими данным необходимо как-то вытащить элемент из одномерного массива. Организовать цикл не получается, потому что не знаю его границ. Думал, может можно как-то узнать размер памяти, которую выделяет malloc и от этого как-то отталкиваться.

PS. заголовок функции менять нельзя. Поля структуры можно

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

20.03.2020, 11:31

Сделать проверку, выделил ли malloc память
Добрый день! Нужна помощь по коду: в строках (34, 45 и 48), где я использовал malloc нужно тут же.

Выделение памяти под структуры (malloc)
Доброго времени суток! Нужна помощь в выделении памяти для структуры с указателями. Можете.

Нужно, чтобы память под массив выделялась не через: new — delete, а через оператор malloc (calloc) — free
Ребят, есть программа, которая работает, но нужно, чтобы память под массив выделялась не через .

Сколько выделится памяти под битовое поле?
Доброго времени суток! Разбираю одну програмку, а именно реализацию телефонной базы данных. Может.

Динамическое выделение памяти под структуру (malloc)
Нашел данное решение на этом форуме, но никак не могу понять как оно работает. Вот даны структуры.

20.03.2020, 11:45 2 20.03.2020, 16:20 3 20.03.2020, 16:52 4
20.03.2020, 16:52
20.03.2020, 17:03 5
20.03.2020, 17:10 6
20.03.2020, 17:13 7

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

Внутри себя менеджер памяти, в котором реализованы malloc, realloc и free, конечно же знает, где сколько памяти выделено. Но по стандарту сия информация не обязана предоставляться наружу, а потому никто её и не предоставляет. Каждая реализация библиотеки работает по своему.

Приведённая тобой формула (даже если исправить синтаксическую ошибку) не учитывает как минимум трёх вещей (т.е. то, что сразу же бросается в глаза):
— размер адресации памяти (ты почему-то решил, что речь идёт обязательно о 32-битной адресации)
— выравнивание памяти (ты не учитываешь того, что служебная информация может быть в обязательном порядке выровнена на величину типа 8 или 16 байт)
— содержимое служебной информации (помимо размера могут храниться какие-то другие служебные данные)

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

Использование стандартных функций malloc и free

Динамическое выделение памяти с помощью библиотечной функции malloc состоит из следующих шагов.

1. Включение в программу файла заголовков malloc.h директивой #include .


2. Объявление указателя нужного типа, например int *p;

3. Вызов функции malloc с указанием в качестве параметра требуемого количества памяти в байтах. Так как функция выдает результат своей работы в виде указателя на тип void, выполняется приведение типа (преобразуется тип результата к типу, указанному в объявлении). Присваивается полученное значение объявленному указателю. Пример:

p=(int *) malloc (число элементов массива*sizeof(int));

Вместо int может быть подставлен любой стандартный или введенный программистом тип.

4. Проверка факта выделения памяти. Если выделение памяти в нужном объеме невозможно, функция malloc возвращает в качестве своего результата нулевой указатель NULL, соответствующий значению ложь. Если выделение памяти выполнено, продолжаем выполнение программы, если нет, выходим из нее с соответствующей диагностикой о недостатке памяти. Пример:

if (!p) сообщение, выход; else продолжение;

5. Освобождение памяти после окончания работы с ней. Для этого вызываем функцию fгее и используем указатель в качестве аргумента:

Значение указателя, полученное после выполнения шага 3, должно сохраняться до выполнения шага 5. В противном случае вся память, выделенная по этому адресу, будет потеряна при выходе из программы, что, в конечном счете, может привести к недостатку памяти и нарушению работы операционной системы.

Наиболее частой причиной «зависания» компьютера при работе с динамически выделяемой памятью является несоответствие инструкций malloc и free (в обеих инструкциях должен использоваться один и тоже указатель) или недостаточный объем свободной памяти.

В качестве примера рассмотрим ввод/вывод одномерного динамического массива произвольной длины, задаваемой с клавиатуры.

int i,n,*massiv; //объявление указателя

cout >n;//ввод размера массива

massiv=(int*)malloc(n*sizeof(int)); //выделение динам.памяти

if(!massiv) //проверка факта выделения памяти

massiv[i]; //ввод массива

Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: Только сон приблежает студента к концу лекции. А чужой храп его отдаляет. 8807 — | 7523 — или читать все.

188.64.174.135 © studopedia.ru Не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования. Есть нарушение авторского права? Напишите нам | Обратная связь.

Отключите adBlock!
и обновите страницу (F5)

очень нужно

Динамическое выделение памяти в Си

Очень часто возникают задачи обработки массивов данных, размерность которых заранее неизвестна. В этом случае возможно использование одного из двух подходов:

  • выделение памяти под статический массив, содержащий максимально возможное число элементов, однако в этом случае память расходуется не рационально;
  • динамическое выделение памяти для хранение массива данных.

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

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

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

Стандартные функции динамического выделения памяти

Функции динамического выделения памяти находят в оперативной памяти непрерывный участок требуемой длины и возвращают начальный адрес этого участка.

Функции динамического распределения памяти:

Для использования функций динамического распределения памяти необходимо подключение библиотеки :

Поскольку обе представленные функции в качестве возвращаемого значения имеют указатель на пустой тип void , требуется явное приведение типа возвращаемого значения.

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

Память, динамически выделенная с использованием функций calloc(), malloc() , может быть освобождена с использованием функции

«Правилом хорошего тона» в программировании является освобождение динамически выделенной памяти в случае отсутствия ее дальнейшего использования. Однако если динамически выделенная память не освобождается явным образом, она будет освобождена по завершении выполнения программы.

Динамическое выделение памяти для одномерных массивов

Форма обращения к элементам массива с помощью указателей имеет следующий вид:

Пример на Си : Организация динамического одномерного массива и ввод его элементов.

Результат выполнения программы:

Динамическое выделение памяти для двумерных массивов

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

index = i*m+j;

где i — номер текущей строки; j — номер текущего столбца.

Рассмотрим матрицу 3×4 (см. рис.)

Индекс выделенного элемента определится как

index = 1*4+2=6

Объем памяти, требуемый для размещения двумерного массива, определится как

n·m·(размер элемента)

Однако поскольку при таком объявлении компилятору явно не указывается количество элементов в строке и столбце двумерного массива, традиционное обращение к элементу путем указания индекса строки и индекса столбца является некорректным:

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

  • p — указатель на массив,
  • m — количество столбцов,
  • i — индекс строки,
  • j — индекс столбца.


Пример на Си Ввод и вывод значений динамического двумерного массива

Возможен также другой способ динамического выделения памяти под двумерный массив — с использованием массива указателей. Для этого необходимо:

  • выделить блок оперативной памяти под массив указателей;
  • выделить блоки оперативной памяти под одномерные массивы, представляющие собой строки искомой матрицы;
  • записать адреса строк в массив указателей.

Графически такой способ выделения памяти можно представить следующим образом.

При таком способе выделения памяти компилятору явно указано количество строк и количество столбцов в массиве.
Пример на Си

Результат выполнения программы аналогичен предыдущему случаю.

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

Для размещения в оперативной памяти матрицы со строками разной длины необходимо ввести дополнительный массив m , в котором будут храниться размеры строк.

Пример на Си : Свободный массив

Перераспределение памяти

Если размер выделяемой памяти нельзя задать заранее, например при вводе последовательности значений до определенной команды, то для увеличения размера массива при вводе следующего значения необходимо выполнить следующие действия:

  • Выделить блок памяти размерности n+1 (на 1 больше текущего размера массива)
  • Скопировать все значения, хранящиеся в массиве во вновь выделенную область памяти
  • Освободить память, выделенную ранее для хранения массива
  • Переместить указатель начала массива на начало вновь выделенной области памяти
  • Дополнить массив последним введенным значением

Все перечисленные выше действия (кроме последнего) выполняет функция

  • ptr — указатель на блок ранее выделенной памяти функциями malloc() , calloc() или realloc() для перемещения в новое место. Если этот параметр равен NULL , то выделяется новый блок, и функция возвращает на него указатель.
  • size — новый размер, в байтах, выделяемого блока памяти. Если size = 0 , ранее выделенная память освобождается и функция возвращает нулевой указатель, ptr устанавливается в NULL .

Размер блока памяти, на который ссылается параметр ptr изменяется на size байтов. Блок памяти может уменьшаться или увеличиваться в размере. Содержимое блока памяти сохраняется даже если новый блок имеет меньший размер, чем старый. Но отбрасываются те данные, которые выходят за рамки нового блока. Если новый блок памяти больше старого, то содержимое вновь выделенной памяти будет неопределенным.

Пример на Си Выделить память для ввода массива целых чисел. После ввода каждого значения задавать вопрос о вводе следующего значения.

Calloc дать память

Есть вещи, в которые многие программисты верят по учебникам, а они уже несколько лет, как потеряли свою актуальность. Большой набор сюжетов такого рода, которые я помню из детства, — про оптимизацию производительности. Сегодня же в 80% случаев лучший совет по ускорению программ, который можно дать программисту, — пиши понятно и сэкономь время друга, который будет читать твой код.

Сюжет, про который пойдет речь в данной статье — почему аллокатор malloc под Linux возвращает очищенную память. Почти как calloc . Более точное утверждение — чистую память возвращают аллокаторы, которые вызываются до первой команды free . Благодаря этому замечательному обстоятельству память, которую процесс qemu-kvm выделяет для создаваемой виртуальной машины, заполнена нулями. Тем самым, создаваемая виртуальная машина не может получить доступ к служебным данным гипервизора и данным других виртуальных машин.

Основные понятия механизмов распределения памяти

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

Аллокаторы и деаллокаторы

Для размещения и удаления объектов в куче используются примитивы создать объект и удалить объект, так называемые аллокаторы и деаллокаторы.

Все аллокаторы и деаллокаторы, включая конструкцию new языка C++, построены на базовых библиотечных функциях malloc и free . Эти функции определяются в стандартной библиотеке языка C, и декларируются в .

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

В Юниксах предыдущего поколения заказ памяти у операционной системы производился утилитами сдвига границы выделяемой памяти brk ( sbrk ). В современных Linux используется ленивое выделение памяти с помощью утилиты mmap , создающей анонимные отображения страниц памяти. Добавлю, что утилита brk присутствует в Линукс и реализована на базе тех же анонимных отображений.

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

Анонимные отображения памяти

Анонимные отображения памяти — отображения памяти в пространство виртуальной памяти процесса, а не файла в пространстве файловой системы. Анонимное отображение схоже со стандартным аллокатором памяти функцией malloc и используется в реализации malloc для запроса памяти у операционной системы. Как следует из описания соответствующего механизма, память при этом инициализируется нулями.

Быстрый эмулятор QEMU

QEMU (Quick EMUlator) — свободная программа с открытым исходным кодом для эмуляции аппаратного обеспечения различных платформ. Автор программы — гениальный французский программист Фабрис Беллар, создатель популярной библиотеки libavcodec и многих других чудесных произведений:

QEMU включает в себя эмуляцию процессоров Intel x86 и устройств ввода-вывода, а также других процессоров. В режиме эмуляции на порядок замедляет исполнение кода. При использовании технологий аппаратной виртуализации (Intel VT и AMD SVM) на x86-совместимых процессорах выдает сопоставимую производительность. Является частью среды виртуализации.

Из исходного кода проекта собирается программа qemu-kvm , которая эмулирует отдельную виртуальную машину. При заказе памяти данная программа пользуется аллокатором phys_mem_alloc :

Описание функции qemu_anon_ram_alloc приводится в файлах oslib-win32.c , oslib-posix.c . В Linux оно основывается на анонимном отображении памяти:

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

Виртуальная машина

Виртуальная машина (ВМ, VM, virtual machine) — в данном контексте это программная система, эмулирующая аппаратное обеспечение x86-совместимого компьютера (включая BIOS, оперативную память, жёсткий диск и другие периферийные устройства) на базе этой же платформы. На ВМ, как и на реальный компьютер, можно устанавливать операционные системы (например, Windows можно запускать в виртуальной машине под Linux или наоборот). На одном сервере может функционировать несколько виртуальных машин. Использование виртуальных машин обеспечивает изоляцию данных между пользователями, работающими в одной вычислительной системе, обеспечивая дополнительный уровень защиты данных.

Концепция виртуальной машины как совокупности ресурсов, которые эмулируют поведение реальной машины, появилась в Кембридже в конце 1960-х годов в виде расширения концепции виртуальной памяти манчестерской вычислительной машины Atlas. В целом вычислительный процесс определяется в рамках этой концепции содержимым того рабочего пространства памяти, к которому он имеет доступ. При условии, что конкретная ситуация в этом рабочем пространстве соответствует ожидаемой, процесс не имеет никаких средств для определения того, является ли представленный ему ресурс действительно физическим ресурсом этого типа, или же он имитируется действиями других ресурсов, которые приводят к аналогичным изменениям содержимого рабочего пространства процесса.

Гипервизор

Гипервизор (hypervisor, монитор виртуальных машин) — минимальная операционная система, обеспечивающая одновременное, параллельное выполнение нескольких или многих гостевых операционных систем на сервере или кластере виртуализации. Он предоставляет запущенным под его управлением операционным системам виртуальные машины. Гипервизор позволяет осуществить независимое включение, выключение, перезагрузку любой из виртуальных машин.

Хороший гипервизор предоставляет дополнительные удобные средства управления виртуальными машинами, такие как сохранение и восстановление состояния машины.

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

Гостевая операционная система

Гостевая операционная система — это операционная система, устанавливаемая на виртуальную машину. Гостевой она называется в отличие от ОС гипервизора, устанавливаемой на физический сервер.

Копирование при записи

Механизм копирования при записи (copy-on-write) используется для оптимизации процесса копирования страниц виртуальной памяти. Сначала в таблице виртуальных страниц обе виртуальные страницы указывают на одну физическую и защищены от записи. При попытке записи создается копия страницы в физической памяти.


Это позволяет существенно ускорить работу функции fork , а также новых файловых систем, таких как ZFS и Btrfs. Другим важным использованием является зануление страниц виртуальной памяти при выделении: они просто помечаются, как копии нулевой страницы ZERO_PAGE .

Куча (heap) — название структуры данных, с помощью которой реализована динамически распределяемая память приложения, а также объём памяти, зарезервированный под эту структуру.

Куча использует память, лениво запрашиваемую по мере необходимости у операционной системы. Эта память используется для размещения объектов, динамически создаваемых и уничтожаемых программой с помощью аллокаторов и деаллокаторов.

Модули ядра KVM

Модули ядра KVM (Kernel-based Virtual Machine) — свободное программное обеспечение, обеспечивающее аппаратную виртуализацию в среде Linux на платформе x86. Базовый сервис виртуализации предоставляется модулем kvm.ko , процессорная специфика содержится в модулях kvm-amd.ko либо kvm-intel.ko .

Эмуляция виртуальных машин осуществляется эмулятором Фабриса Белларда QEMU. Эта программа, работающая в пространстве пользователя, использует интерфейс /dev/kvm для настройки адресного пространства виртуальной машины, через него же эмулирует устройства ввода-вывода и видеоадаптер.

Для данного обсуждения необходимо понимать, что хотя KVM является важной и сложной частью процесса виртуализации, он не участвует в выделении оперативной памяти для виртуальных машин. Этим занимается QEMU, или, более точно, программа qemu-kvm , которая, в свою очередь, использует традиционные аллокаторы памяти.

Операционная система

Операционная система (ОС, operating system, OS) — комплекс программ, которые, с одной стороны, выступают как унифицированный интерфейс между устройствами вычислительной системы и прикладными программами, а с другой стороны предназначены для управления устройствами, вычислительными процессами, распределения вычислительных ресурсов и организации надежных и безопасных вычислений.

Отложенная инициализация

Отложенная (ленивая) инициализация, (lazy initialization) — прием в программировании, когда некоторая ресурсоемкая операция (создание объекта, вычисление значения) выполняется непосредственно перед тем, как будет использован ее результат. Таким образом, инициализация выполняется по требованию, а не заблаговременно. Аналогичная идея находит применение в самых разных областях:

  • при компиляции на лету метод компилируется непосредственно перед исполнением;
  • при использовании отображений памяти страница загружается с диска, когда к ней происходит обращение;
  • при динамическом управлении памятью новая страница памяти для кучи запрашивается у операционной системы только в случае необходимости.

Отображение памяти

Вызов mmap — вызов Linux, позволяющий выполнить отображение файла или устройства на память. Используется для ленивого ввода-вывода. Файловые отображения позволяют отобразить файл в виртуальную память. Доступ к этим участкам памяти приводит к чтению или изменению файла.

Также используется как менеджер памяти для выделения страниц по запросу (в анонимном режиме). При этом операционная система обнуляет выделяемую область памяти.

Отображаемая память при завершении процесса или использовании munmap , если только отображение не является публичным и не зарезервировано в файле. Сегмент памяти, созданный mmap , автоматически удаляется ядром системы, когда завершается его использование.

Вызов mmap , который может использоваться пользовательской программой для создания отображений памяти, описывается в стандартной библиотеке glibc и выполняется ядром операционной системы.

Сервер управления доступом FreeIPA

Сервер управления доступом IPA (Identity, Policy and Audit) это свободный программный продукт для создания централизованной системы для идентификации пользователей и задания политик доступа, система обеспечения безопасности в средах виртуализации.

Система управления виртуализацией oVirt

oVirt — свободная, кроссплатформенная система управления виртуализацией. Позволяет управлять гипервизором и образами виртуальных машин на базе технологии KVM+QEMU посредством веб-интерфейса, используя для администрирования библиотеку libvirt .

Среда виртуализации Red Hat Enterprise Virtualization

Red Hat Enterprise Virtualization (RHEV) — корпоративный продукт, обеспечивающий возможности виртуализации. Основан на свободных продуктах: модуле ядра KVM, эмуляторе QEMU, сервере управления доступом FreeIPA и веб-приложении управления виртуализацией oVirt.

Механизм, реализующий анонимные отображения памяти

Вызов mmap , который может использоваться пользовательской программой для создания отображений памяти, описывается в стандартной библиотеке glibc в соответствии с таблицей системных вызовов ядра. Соответствующий системный вызов sys_mmap определяется в sys_x86_64.c : он конвертирует смещение offset из байтов в страницы и вызывает системный вызов sys_mmap_pgoff . Префикс sys_ добавляется макросами SYSCALL_DEFINE6 и SYSCALL_DEFINEx .

Системный вызов sys_mmap_pgoff определяется следующим образом: системный вызов находит файл, соответствующий аргументу типа struct file * и вызывает vm_mmap_pgoff .

Вызов vm_mmap_pgoff после проверок безопасности вызывает do_mmap_pgoff .

Функция do_mmap_pgoff определяет ищет цепочку последовательных свободных страниц для создания отображения с помощью функций get_unmapped_area , находит адрес начала отображения addr и передает его в mmap_region . Для определенных устройств, которые умеют себя отображать только на конкретные адреса памяти и определяют свой f_op->mmap , значение addr может поменяться, что требует дополнительных проверок и потенциально может привести к неуспеху mmap , если мы попадем на занятую память.

Функция mmap_region создает структуру типа vm_area_struct , описывающую новый регион памяти.

Выделяемые страницы отображения изначально защищены от обращений. Когда программа обращается к защищенной странице, срабатывает перехватчик handle_pte_fault :

Перехватчик handle_pte_fault вызывает do_no_page :

Если размер страницы виртуальной памяти равен 4 Кбайт, то в функции do_anonymous_page выдаваемая страница помечается копией в режиме копирования при записи от ZERO_PAGE (нулевой страницы). Если система переконфигурирована для работы со страницами большого (2 Мбайт или 1 Гбайт) размера, то обнуление происходит в функции do_huge_pmd_anonymous_page . Размер страницы можно узнать с помощью getconf PAGESIZE .

Механизм выделения памяти для виртуальных машин

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

  1. Администратор создает виртуальную машину.
  2. Память виртуальной машины создается библиотечным вызовом mmap — анонимно для новой машины или из файла.
  3. Как следует из описания работы отображений памяти, память заполняется нулями.

В чем разница между malloc() и calloc() а также free() и dellete()?

Допустим мы выделаем память

У них есть 2 разницы
calloc выделяет память под массив данных, предварительно инициализируя её нулями. принимает 2 аргумента.
malloc выделяет память без инициализации. принимает один аргумент.

Но в принципе оба эти функций делают одно и тоже, в чем их разница ?
Где то читал что calloc создает ячейки определенного типа и обединяет их, к примеру int может быть 4 байта, и если мы напишем
int *y = (int*) calloc(3, sizeof(int));
То он создаст 12 ячеек, 4 4 4 и в каждом из 4 байтов будет храниться цифра 0.

int *x = (int*) malloc(12);
Тоже создаст 12 ячеек но если к примеру, в него добавим первый 4 байт цифру 9, в другой байт «string», а в другой вообще bool, как он определит что в нем находиться ?

Если в случае с calloc он знает что через каждые 4 байта у него есть цифра, то как в malloc он определит, что через каждые разные количество байтов у него разные количество элементов, Или он определяет свои элементы совсем по другому, в этапе компиляций и т.д.?

  • Вопрос задан более года назад
  • 959 просмотров

Разница только в том, что calloc обнуляет выделенную память перед тем, как возвратить указатель, а malloc этого не делает. Внутри calloc, наверняка вызывает malloc для выделения памяти, а потом memset для обнуления. Так что calloc это просто надстройка над malloc для удобства. Вот схематично реализация calloc:

Сами эти функции оперируют исключительно размером выделяемой области в байтах, им все равно что вы в дальнейшем будете делать с выделенной памятью — инты туда писать или «стринги».
Ну и как бы никто не мешает вам одну и ту же область памяти сначала использовать как массив интов, а потом как массив байт. Или так например:

Пример не использует malloc/calloc для выделения памяти, память выделяется в стеке просто объявлением int a. Тут я попытался показать, что содержимое памяти можно интерпретировать как угодно, главное находится в границах выделенного диапазона.
Причем языки С/С++/asm это позволяют делать, а другие — нет.
Пример предполагает, что int имеет размер 32 бита, не для всех платформ это так, но в основном — именно так.
Кстати этот пример можно использовать для определения порядка байтов платформы: если выведется «1 2 3 4» значит у вас LITTLE ENDIAN, а если «2 1 4 3» — BIG ENDIAN.

PS: free() — это Си, а delete — C++

А free и delete ведут себя идентично ?
Оба ставят метку на область памяти, и считают эту область мусором или все данные в этой области становятся нулями ?
И еще delete вызывает деструктор, а free нет тогда как он освобождает память ?
В некоторых руководствах пишут, что


Так значит free просто отнимает память ?

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

Для данной конкретной ОС и настроек компилятора по значению this можно предположить где выделена память, но в общем случае — нет. Кроме того, память может быть выделена не для одного объекта (деструктор которого вызван), а для массива объектов. Что вы будете освобождать в этом случае?
Поэтому вызов деструктора в delete здесь не к месту упомянут. И да, в С++ используется именно delete потому что на нем завязана дополнительная функциональность по вызову деструктора.

Да, free просто освобождает память.
Вызов realloc в вашем примере освободит память выделенную для х и вернет нулевой указатель.

Есть некоторое количество разных реализаций менеджеров памяти, которые по разному реализуют malloc/free. В своем проекте вы можете использовать сторонний менеджер памяти, а не тот что предлагается по умолчанию. Кроме того в ОС есть собственный менеджер памяти и можно использовать его. В винде это функции LocalAlloc/LocalFree и еще пачка других.

И еще вот такой вопрос, касательно malloc`a и calloc`

Допустим память выделяется вот так

в calloc храним только Int → 1, 2, 4, 3 каждое из которых 4 байт = 16 байт.
А в malloc храним int 1 → char a, b → double int 5, получается у нас 4байт + 2 + 8 = 14 байт.

Вот как тут компилятор, процессор или не знаю что) понимает что именно находится в этих ячеек ?

Если предположить с логикой, то можно понять что calloc уже знает что через каждые 4 байта у него внутри число типа int. (Я точно не знаю так ли это работает)

Тогда как malloc не знает через сколько шагов что именно у него внутри.

Вот как тут компилятор, процессор или не знаю что) понимает что именно находится в этих ячеек ?

Dynamic Memory Allocation in C using malloc(), calloc(), free() and realloc()

Изменение длины (размера) массива, где массив это набор элементов, хранящихся в ячейках памяти расположенных одна за другой.

Как вы можете видеть на изображении выше длина (размер) массива равна 9. Но что если требуется уменьшить длину, например, с 9 до 5 элементов, чтобы не расходовать память понапрасну?
Или наоборот, если массив из 9 элементов заполнен до конца, то увеличить его, например до 12?

В этом случае используется динамическое выделение памяти (Dynamic Memory Allocation).

C располагает для этого 4 функциями, которые подключаются заголовочным файлом и реализуют выделение памяти в С. Вот они:

Рассмотрим каждую из них подробнее:

malloc()

“malloc” или “выделение памяти” метод для динамического выделения одного большого блока памяти заданного размера.
Функция возвращает указатель типа void , который может быть присвоен указателю (pointer) любого типа.

Т.к. размер int равен 4-м байтам,
это выражение выделит 20 байт памяти.
Указатель ptr будет содержать
первый байт выделенной области памяти.

Если же места недостаточно, выделение завершится неудачно и будет возвращён указатель NULL.

calloc()

“calloc” или “последовательное распределение” метод динамического выделения заданного кол-ва блоков указанного размера. При инициализации каждый блок получает значение по умолчанию — ‘0’.

Данное выражение выделяет непрерывное пространство в памяти
для 5-ти элементов, каждый из которых имеет размер 4 байта.

Если места недостаточно, возвращается указатель NULL.

“free” — метод используемый для освобождения (de-allocated) памяти выделенной при помощи функций malloc и calloc , которые сами по себе не могут освободить её. Это помогает уменьшить потери памяти.

realloc()

“realloc” или “перераспределение памяти” — метод позволяющий перераспределять память. Если памяти выделенной до этого при помощи функций malloc и calloc недостаточно, при помощи realloc можно перераспределить её.

где ptr это перераспределяемая область с новым размером ‘newSize’.

Если же места недостаточно, указатель возвращает NULL.

Разница между malloc и памятью?

в чем разница между:

когда это хорошая идея, чтобы использовать calloc над malloc или наоборот?

18 ответов:

calloc() ноль-инициализирует буфер, в то время как malloc() оставляет память неинициализированной.

EDIT:

вычеркивать из памяти может занять немного времени, так что вы, вероятно, хотите использовать malloc() если производительность является проблемой. Если инициализация памяти более важна, используйте calloc() . Например, calloc() может сохранить вам вызов memset() .

менее известная разница заключается в том, что в операционных системах с оптимистичным выделением памяти, таких как Linux, указатель возвращается malloc не поддерживается реальной памятью, пока программа не коснется ее.

calloc действительно касается памяти (она записывает на нее нули), и поэтому вы будете уверены, что ОС поддерживает выделение с фактической ОЗУ (или свопом). Именно поэтому он медленнее, чем malloc (мало того, что он должен обнулить его, ОС также должна найти подходящую область памяти возможно замена других процессов)

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

одно часто упускаемое из виду преимущество calloc это (соответствующие реализации) это поможет защитить вас от целочисленных уязвимостей переполнения. Сравните:

первый может привести к крошечному выделению и последующему переполнению буфера, если count больше SIZE_MAX/sizeof *bar . Последний автоматически завершится неудачей в этом случае, так как объект, который большой не может быть создан.

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

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

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

нет никакой разницы в размере выделенного блока памяти. calloc просто заполняет блок памяти физическим шаблоном всех нулевых битов. На практике часто предполагается, что объекты, расположенные в блоке памяти, выделяются с помощью calloc имеют начальное значение, как если бы они были инициализированы литералом 0 , т. е. целые числа должны иметь значение 0 , переменные с плавающей запятой-значение 0.0 , указатели-соответствующее значение нулевого указателя, и так далее.

от педантичная точка зрения, однако, calloc (а также memset(. 0, . ) ) гарантируется только правильная инициализация (с нулями) объектов типа unsigned char . Все остальное не гарантируется для правильной инициализации и может содержать так называемый ловушка представление, что вызывает неопределенное поведение. Другими словами, для любого типа, кроме unsigned char вышеупомянутый все-нулевой бит паттерн может представлять собой незаконное значение, представление ловушку.

позже, в одном из Технические исправления к стандарту C99, поведение было определено для всех целочисленных типов (что имеет смысл). Т. е. формально в текущем языке C вы можете инициализировать только целочисленные типы с помощью calloc (и memset(. 0, . ) ). Используя его для инициализации и все остальное в общем случае приводит к неопределенному поведению, с точки зрения языка Си.

на практике calloc работает, как мы все знаем :), но хотите ли вы его использовать (учитывая вышеизложенное), зависит от вас. Лично я предпочитаю избегайте его полностью, используйте malloc вместо этого и выполните мою собственную инициализацию.


наконец, еще одна важная деталь заключается в том, что calloc требуется для расчета конечного размера блока внутри, путем умножения размера элемента на количество элементов. А делать, что calloc необходимо следить за возможным арифметическим переполнением. Это приведет к неудачному выделению (нулевой указатель), если запрошенный размер блока не может быть правильно вычислен. Между тем, ваш malloc версия не делает никаких попыток следить за переполнением. Он выделит некоторый «непредсказуемый»объем памяти в случае переполнения.

при выделении памяти с помощью calloc (), объем запрашиваемой памяти не выделяется сразу. Вместо этого все страницы, принадлежащие блоку памяти, соединяются с одной страницей, содержащей все нули, с помощью некоторой магии MMU (ссылки ниже). Если такие страницы только читаются (что было верно для массивов b, c и d в исходной версии benchmark), данные предоставляются с одной нулевой страницы, которая – конечно же – помещается в кэш. Так много для ядер цикла с привязкой к памяти. Если страница записывается (независимо от того, как), возникает ошибка, «реальная» страница сопоставляется и нулевая страница копируется в память. Это называется copy-on-write, хорошо известный подход к оптимизации (который я даже преподавал несколько раз в своих лекциях на C++). После этого трюк с нулевым чтением больше не работает для этой страницы, и именно поэтому производительность была такой высокой понизьте после вставки-предположительно избыточного-цикла инициализации.

calloc обычно malloc+memset до 0

обычно немного лучше использовать malloc+memset явно, особенно, когда вы делаете что-то вроде:

что лучше, потому что sizeof(Item) известно компилятору во время компиляции, и компилятор в большинстве случаев заменит его наилучшими инструкциями к нулевой памяти. С другой стороны, если memset происходит calloc , размер параметра распределения не компилируется в calloc код и реальные memset часто вызывается, который обычно содержит код, чтобы сделать байт за байтом заполнить до длинной границы, чем цикл, чтобы заполнить память в sizeof(long) куски и, наконец, байт за байтом заполняют оставшееся пространство. Даже если распределитель достаточно умен, чтобы вызвать некоторые aligned_memset это все равно будет общая петля.

одно заметное исключение будет, когда вы делаете malloc / calloc очень большой кусок памяти (некоторые power_of_two килобайт) в этом случае выделение может быть сделано непосредственно из ядра. Поскольку ядра ОС обычно обнуляют всю память, которую они отдают по соображениям безопасности,достаточно умный calloc может просто вернуть ее с дополнительным обнулением. Опять же — если вы просто выделяете что-то, что вы знаете, мало, вам может быть лучше с производительностью malloc+memset.

malloc() выделяет блок памяти заданного размера (в байтах) и возвращает указатель на начало блока.

malloc() не инициализирует выделенную память.

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

Разница 1: malloc () обычно выделяет блок памяти и инициализирует сегмент памяти. calloc () выделяет блок памяти и инициализирует весь блок памяти до 0.

разница 2: Если вы рассматриваете синтаксис malloc (), он будет принимать только 1 аргумент. Рассмотрим следующий пример:

data_type ptr = (cast_type *) malloc( sizeof(data_type)*no_of_blocks);

пример: Если вы хотите выделить 10 блоков памяти для int типа,

Если вы рассматриваете синтаксис calloc (), он будет принимать 2 аргумента. Рассмотрим следующий пример:

data_type ptr = (cast_type *)calloc (no_of_blocks, (sizeof (data_type)));

пример: если вы хотите выделить 10 блоков памяти для типа int и инициализировать все это до нуля,

и malloc() и calloc () вернут void* по умолчанию, если они не являются приведенными типами .!

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

  • calloc() выделяет область памяти, длина будет произведением ее параметров. calloc заполняет память нулями и возвращает указатель на first байт. Если он не может найти достаточно места, он возвращает NULL указатель.

синтаксис: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block); то есть ptr_var=(type *)calloc(n,s);

  • malloc() выделяет один блок памяти требуемого размера и возвращает указатель на первый байт. Если ему не удается найти требуемый объем памяти, он возвращает нулевой указатель.

синтаксис: ptr_var=(cast_type *)malloc(Size_in_bytes); Элемент malloc() функция принимает один аргумент, который является количеством байтов для выделения, в то время как calloc() функция принимает два аргумента, один из которых-количество элементов, а другой-количество байтов, выделяемых для каждого из этих элементов. Кроме того, calloc() инициализирует выделенную память нулями, в то время как malloc() нет.

The calloc() функция, которая объявлена в заголовок предлагает несколько преимуществ по сравнению с

разница еще не упомянул: лимит в размере

void *malloc(size_t size) можно выделить только до SIZE_MAX .

void *calloc(size_t nmemb, size_t size); можно выделить о SIZE_MAX*SIZE_MAX .

эта способность не часто используется во многих платформах с линейной адресации. Такие системы ограничивают calloc() С nmemb * size .

рассмотрим тип 512 байт под названием disk_sector и код хочет использовать много секторов. Здесь код может использоваться только до SIZE_MAX/sizeof disk_sector сектора.

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

теперь, если такая система может обеспечить такое большое распределение, это другое дело. Большинство сегодня не будет. Тем не менее, это произошло в течение многих лет, когда SIZE_MAX было 65535. Учитывая закон Мура, подозреваю, что это будет происходить около 2030 года с некоторыми моделями памяти с SIZE_MAX == 4294967295 и пулы памяти в 100 Гбайт.

malloc (): выделяет запрошенный размер байтов и возвращает указатель первый байт выделенного пространства

calloc (): выделяет пространство для элементов массива, инициализирует до нуля, а затем возвращает указатель на память

malloc() и calloc() являются функциями из стандартной библиотеки C, которые позволяют динамическое выделение памяти, что означает, что они оба позволяют выделение памяти во время выполнения.

их прототипы выглядят следующим образом:

есть в основном два различия между ними:

поведение: malloc() выделяет блок памяти, не инициализируя его, и чтение содержимого из этого блока приведет к значениям мусора. calloc() , с другой стороны, выделяет блок памяти и инициализирует его нулями, и, очевидно, прочитав содержимое этого блока приведет к нулям.

синтаксис: malloc() принимает 1 аргумент (размер, который будет выделен), и calloc() принимает два аргумента (количество выделяемых блоков и размер каждого блока).

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

пример:

та же функциональность, что и calloc() может быть достигнуто с помощью malloc() и memset() :

отметим, что malloc() предпочтительно использовать более calloc() так как это быстрее. Если требуется нулевая инициализация значений, используйте .

основные различия между malloc и calloc являются:

    malloc означает выделение памяти в то время как calloc означает непрерывные распределения.

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

ptr = (cast-type*) malloc (размер байта) // Мэллок

ptr = (cast-type*)calloc (нет блоков, размер блока); // calloc


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

имя malloc и calloc () — это библиотечные функции, которые динамически выделяют память.
Это означает, что память выделяется во время выполнения(выполнение программы) из сегмента кучи.

инициализации: malloc() выделяет блок памяти заданного размера (в байтах) и возвращает указатель на начало блока.

ряд аргументов: в отличие от malloc (), calloc () принимает два аргумента: 1) количество выделяемых блоков. 2) Размер из каждого блока.

было бы лучше использовать malloc над calloc, если мы не хотим нулевой инициализации, потому что malloc быстрее, чем calloc. Так что если мы просто хочу скопировать некоторые вещи или сделать что-то, что не требует заполнение блоков нулями, тогда Мэллок будет лучше выбор.

malloc() принимает один аргумент, в то время как calloc () принимает два.

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

просто выделяет n bytes памяти без какой-либо инициализации (т. е. эти байты памяти будут содержать любые значения мусора).

, calloc() метод в c выполняет инициализацию как 0 значение для всех занятых байтов памяти в дополнение к функции, которая malloc() делает.

но кроме этого, есть очень важное отличие. Во время вызова malloc(x) он выделит память (равную X блокам) и вернет указатель на первый выделенный байт. Однако, он не будет проверять, если точно х блоков памяти. Это приведет к переполнению памяти. Однако calloc() проверяет размер выделения. Если он не справляется с выделением памяти или проверкой выделенных байтов, он просто возвращает null.

Программирование: Разработка и отладка программ

Для приложений память выделяется с помощью подсистемы malloc. Подсистема malloc — это API для управления памятью, состоящий из следующих функций:

  • malloc
  • calloc
  • realloc
  • free
  • mallopt
  • mallinfo
  • alloca
  • valloc

Подсистема malloc управляет объектом логической памяти, который называется кучей. Куча — это область памяти в адресном пространстве приложения, расположенная после последнего байта данных, размещенного компилятором. Память кучи выделяется и освобождается с помощью API подсистемы malloc.

Подсистема malloc выполняет три базовые операции с памятью: выделение, освобождение и изменение размера области памяти. Для выделения памяти служат функции malloc и calloc , для освобождения — функция free , а для изменения размера — функция realloc . Функции mallopt и mallinfo поддерживаются для совместимости c System V. Функция mallinfo может применяться для получения информации о куче, с которой работает функция malloc , во время создания программы. С помощью функции mallopt можно освобождать память блоками, кратными размеру страницы и выровненными по границе страницы, а также отключить стандартную процедуру распределения памяти. Функция valloc аналогична malloc и поддерживается для совместимости со стандартом Berkeley.

Адресное пространство 32-разрядных прикладных программ разделяется в системе на семь сегментов:

С 0x00000000 по 0x0fffffff Содержит ядро.
С 0x10000000 по 0x1fffffff Содержит текст прикладной программы.
С 0x20000000 по 0x2fffffff Содержит данные и стек прикладной программы.
С 0x30000000 по 0xafffffff Общая память и память служб mmap .
С 0xd0000000 по 0xdfffffff Содержит текст общей библиотеки.
С 0xe0000000 по 0xefffffff Содержит данные ядра.
С 0xf0000000 по 0x0fffffff Содержит данные общей библиотеки приложения.

Адресное пространство 64-разрядных приложений разделяется в системе на семь сегментов:

С 0x0000 0000 0000 0000 по 0x0000 0000 0fff ffff Содержит ядро.
С 0x0000 0000 d000 0000 по 0x0000 0000 dfff ffff Содержит информацию общей библиотеки.
С 0x0000 0000 e000 0000 по 0x0000 0000 efff ffff Содержит данные ядра.
С 0x0000 0000 f000 0000 по 0x0000 0000 0fff ffff Зарезервировано.
С 0x0000 0001 0000 0000 по 0x07ff ffff ffff ffff Содержит текст, данные и стек прикладной программы, а также общую память и память служб mmap .
С 0x0800 0000 0000 0000 по 0x08ff ffff ffff ffff Защищенные объекты.
С 0x0900 0000 0000 0000 по 0x09ff ffff ffff ffff Текст и данные общей библиотеки.
С 0x0f00 0000 0000 0000 по 0x0fff ffff ffff ffff Стек приложения.

На первый байт, следующий после последнего байта данных программы, указывает переменная _edata. Подсистема malloc создает кучу при размещении первого блока данных. Функция malloc создает кучу путем перемещения указателя _edata и освобождения области памяти для кучи с помощью функции sbrk . После этого функция malloc расширяет кучу в соответствии с требованиями приложения. Размер области памяти, добавляемой при расширении кучи, задается переменной BRKINCR . Для просмотра этого значения предназначена функция mallinfo .

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

Стратегия выделения памяти связана с набором структур данных и алгоритмов, на основе которых моделируется куча и реализуются операции выделения, освобождения и изменения размера области памяти. Подсистема malloc поддерживает две стратегии выделения памяти: стандартную стратегию и стратегию, применявшуюся вплоть до версии 3.1. В обеих стратегиях выделения памяти используется один и тот же интерфейс подсистемы malloc.

Стандартная стратегия более эффективна для большинства типичных приложений. Отдельные особенности стратегии 3.1 могут дать выигрыш в ряде нестандартных ситуаций. Подробные сведения об этом приведены в разделе Различия между стандартной стратегией и стратегией 3.1. Стратегию 3.1 можно применять только с 32-разрядными приложениями. Она не работает в 64-разрядной среде.

В стандартной стратегии распределения памяти свободная память кучи представляется в виде дерева свободных блоков. Дерево свободных блоков — это двоичное дерево, узлы которого отсортированы по вертикали в соответствии с размером блоков и по горизонтали — в соответствии с адресом. Такая структура данных не накладывает ограничения на размер блоков, поддерживаемых деревом, позволяя работать с блоками любого размера. Алгоритмы реорганизации дерева позволяют оптимизировать время поиска, вставки и удаления узлов, а также решают проблему фрагментации.

С помощью функции roundup подсчитывается размер запрошенного блока в байтах. Формат:

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

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

Блоки памяти освобождаются с помощью функции free и помещаются в корень дерева свободных блоков. Для всех узлов, расположенных в дереве выше позиции вставки нового узла, выполняется проверка, не являются ли они смежными с добавляемым блоком. Если да,то два узла объединяются, и в дерево добавляется узел для объединенного блока. Уровень, на котором будет расположен узел в дереве, зависит от его размера. Если смежные узлы не найдены, то узел просто располагается в соответствующей позиции дерева. Объединение смежных блоков позволяет значительно снизить степень фрагментации кучи.

Если размер запрошенного блока больше размера исходного блока, то исходный блок возвращается в дерево свободных блоков с помощью функции free . В результате он объединяется со всеми свободными смежными блоками. После этого выделяется новый блок запрошенного размера, данные копируются из исходного блока в новый, после чего он возвращается инициатору.

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

Для применения стратегии распределения памяти 3.1 нужно выполнить следующие команды:

После этого все 32-разрядные программы, запущенные из данной оболочки, будут применять стратегию распределения памяти 3.1 (63-разрядные по-прежнему будут пользоваться стандартной стратегией). Если переменной MALLOCTYPE будет присвоено любое другое значение, то будет применяться стандартная стратегия.

В стратегии 3.1 куча представляет собой набор из 28 хэш-блоков, каждый из которых указывает на список. Хэширование — это способ преобразования ключа поиска в адрес с целью чтения или записи элемента данных. Такой способ позволяет минимизировать среднее время поиска. Хэш-блок содержит одно или несколько полей, хранящих результат операции. Каждый список содержит блоки определенного размера. Индекс хэш-блока определяет размер блоков в связанном с ним списке. Размер блока вычисляется по следующей формуле:

где i — это номер хэш-блока. Это означает, что нулевой хэш-блок ссылается на список из блоков 2 0+4 = 16 байт длиной. Если предположить, что префикс занимает 8 байт, такие блоки могут применяться для запросов на область памяти размером от 0 до 8 байт. В приведенной ниже таблице показана взаимосвязь между размером запрошенной области памяти и хэш-блоками.

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








Стратегия 3.1
Хэш-блок Размер блока Диапазон запросов Число требуемых страниц
16 0 . 8
1 32 9 . 24
2 64 25 . 56
3 128 57 . 120
4 256 121 . 248
5 512 249 . 504
6 1 Kб 505 . 1 Кб — 8
7 2 Кб 1 Кб — 7 . 2 Кб — 8
8 4 Кб 2 Кб — 7 . 4 Кб — 8 2
9 8 Кб 4 Кб-7 . 8 Кб — 8 3
10 16 Кб 8 Кб — 7 . 16 Кб — 8 5
11 32 Кб 16 Кб — 7 . 32 Кб — 8 9
12 64 Кб 32 Кб — 7 . 64 Кб — 8 17
13 128 Кб 64 Кб-7 . 128 Кб-8 33
14 256 Кб 128 Кб-7 . 256 Кб-8 65
15 512 Кб 256 Кб-7 . 512 Кб-8 129
16 1 Мб 256 Кб-7 . 1 Мб-8 257
17 2 Мб 1 Мб-7 . 2 Мб-8 513
18 4 Мб 2 Мб-7 . 4 Мб-8 1 Кб + 1
19 8 Мб 4 Мб-7 . 8 Мб-8 2 Кб + 1
20 16 Мб 8 Мб-7 . 16 Мб-8 4 Кб + 1
21 32 Мб 16 Мб-7 . 32 Мб-8 8 Кб + 1
22 64 Мб 32 Мб-7 . 64 Мб-8 16 Кб + 1
23 128 Мб 64 Мб-7 . 128 Мб-8 32 Кб + 1
24 256 Мб 128 Мб-7 . 256 Мб-8 64 Кб + 1
25 512 Мб 256 Мб-7 . 512 Мб-8 128 Кб + 1
26 1024 Мб 512 Мб-7 . 1024 Мб-8 256 Кб + 1
27 2048 Мб 1024 Мб-7 . 2048 Мб-8 512 Кб + 1

Перед выделением блока из пула свободных блоков число запрошенных байт преобразуется в индекс массива хэш-блоков по следующей формуле:

Размер блоков в списке, на который ссылается хэш-блок, можно вычислить по формуле: размер блока = 2 хэш-блок + 4 . Если список, на который ссылается хэш-блок, пустой, то в него добавляются блоки путем выделения памяти с помощью функции sbrk . Если размер блока меньше страницы, то функция sbrk выделяет страницу. При этом число блоков, добавленных в список, равно размеру страницы, поделенному на размер блока. Если размер блока больше либо равен размеру страницы, необходимый объем памяти выделяется с помощью функции sbrk , и к списку свободных блоков хэш-блока добавляется всего один блок. Если список свободных блоков не пуст, то инициатору возвращается первый блок списка. При этом указатель на начало списка связывается со следующим блоком.

При освобождении блока памяти, как и при выделении, подсчитывается индекс хэш-блока. После этого освобожденный блок добавляется в начало списка свободных блоков хэш-блока.

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

Стратегию 3.1 можно применять только с 32-разрядными приложениями. Даже если для 64-разрядной программы будет указано значение MALLOCTYPE=3.1, для нее будет применяться стандартная стратегия.

Стратегия 3.1 не поддерживает следующие функции:

  • Сложная куча malloc
  • Блоки malloc
  • Отладчик malloc

Стратегия 3.1 широко применяется в системах UNIX. Ее существенный недостаток заключается в том, что при выделении памяти размер запрошенной области округляется вверх до ближайшего числа, являющегося степенью числа 2. Это приводит к существенной фрагментации виртуальной и оперативной памяти и ряду других проблем. В стандартной стратегии отводится ровно столько памяти, сколько было запрошено, и применяются усовершенствованные средства контроля освободившихся областей памяти.


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

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

Если программа регулярно увеличивает размер выделенной области памяти с помощью функции realloc , то в стратегии 3.1 с меньшей вероятностью потребуется перемещать эту область. Во многих случаях функции realloc будет достаточно «избыточной» памяти, которая была выделена с самого начала за счет округления запрошенного размера области. В стандартной стратегии в таких случаях область памяти почти всегда перемещается, потому что с большой вероятностью вся память вокруг увеличиваемой области будет занята. В таких ситуациях стратегия 3.1 будет выигрывать по производительности у стандартной стратегии. На самом деле такой выигрыш будет обеспечиваться только за счет характерных недостатков в алгоритме программы.

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

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

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

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

Самостоятельно что ли? Зачем бы ему это делать, если система выделяет память обнулённую. Разве что если маленькими частями выделять.

если система выделяет память обнулённую

С каких пор? Куча всегда с говном выделяется!

Всегда так было как только научились думать о безопасности, не? Я говорю о памяти, которая приходит от системы в результате sbrk или mmap, а не которая уже была в использовании этим приложением. Она же и приводит к оверкоммиту. Теоретически ядро может отдать ранее освобождённую страницу от этого же процесса, но оно так вроде не делает.

Как страшно ЖЫТЬ! Я и не думал про то, что выделение больших объемов calloc’ом аналогично malloc’у. Блин, надо будет переделать свой макрос MALLOC, безопасно выделяющий память! Вместо calloc впихну туда malloc с memset.

Это ж банальный оверкоммит

А в мане написано зануленная

Ох уж эта борьба сишников с ОС.

enjoy your abstraction!

Это не оверкоммит. Я уже 20тысяч раз это объяснял. Это свойство реальности, а оверкоммит — это механизм именно подавления этого поведения.

Т.е. На самом деле включение оверкоммита его выключает, а выключение — включает.

Вот так всегда. Рассуждает о банальностях, но таких банальностей не знаешь.

Ещё один… Это уже как минимум третий тред на моей памяти.

Эдик, мемсет тебе не поможет и я уже 20тысяч раз говорил почему. Тебе поможет только mmap + map_populate и ничего более.

Я и не думал про то, что выделение больших объемов calloc’ом аналогично malloc’у.

Это уже тысячи раз обсуждали и я не знаю куда вы смотрели.

Давай ещё больше сломаю твой шаблон.

Ну это уж совсем костыль получится. Но ладно, учту, что большие куски памяти можно только вручную mmap’ом выделять и не полагаться вообще на malloc/calloc.

Мимо ушей как-то пролетело.

Как сложно жить, не читая документации. Что Эдику, что топикстартеру.

Т.е. На самом деле включение оверкоммита его выключает, а выключение — включает.

Что я только что прочитал?

Но ладно, учту, что большие куски памяти можно только вручную mmap’ом выделять и не полагаться вообще на malloc/calloc.

Не просто ммапом, ммап у тебя так же может отвалиться(на мемсете). Именно с map_populate.

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

Это очень сильно запутало всех адептов 286-го, которые с чего-то взяли, что подобное поведение — это следствие какого-то магического оверкоммита, что, естественно, никакого отношения к реальности не имеет.

Вот и повторяют этот миф от случая к случаю, а документация их путает.

В ядре реализован механизм, который ничего не делает тогда, когда включен.

А включен он по умолчанию.

Это очень сильно запутало всех адептов 286-го, которые с чего-то взяли, что подобное поведение — это следствие какого-то магического оверкоммита, что, естественно, никакого отношения к реальности не имеет. Вот и повторяют этот миф от случая к случаю, а документация их путает.

Я хз, что ты придумал, но оверкоммитом принято называть удовлетворение запросов анонимной памяти без ограничений. Что в современных никсах очень естественно, потому что ограничений памяти как таковых там нет, есть лишь хоровод страниц в NRU-списке, который ядро тасует туда-сюда между блочными устройствами и ОЗУ.

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

Не включен. Включен он частично, да и из этого ничего не следует.

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

Не принято. Оверкоммитом ошибочно называют механизм с аналогичным названием, который и наделяют источником подобных свойств «работы» памяти.

Что в современных никсах очень естественно, потому что ограничений памяти как таковых там нет, есть лишь хоровод страниц в NRU-списке, который ядро тасует туда-сюда между блочными устройствами и ОЗУ.

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

Подобное поведения — это новшества 386 вкупе с семантикой ммапа, да и много чего ещё. Иначе этого не сделать — т.е. нельзя эмулировать прямое отображение.

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

Его нельзя выключить — его можно только ограничить. И то это не сработает в полной мере. И именно эта программная логика в ядре и называется «оверкоммит, которая частично включена. В частности, она не даст тебе выделить кусок длиннее длинны свободной рамы.

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

Подобное поведения — это новшества 386

Ага, может еще и процессоры как таковые в Intel придумали?


Иначе этого не сделать — т.е. нельзя эмулировать прямое отображение.

Ага, может еще и процессоры как таковые в Intel придумали?

Никто ни о каких процессорах не говорил, об 386 говорилось в контексте сравнения его с 286, а именно интел взялся потому, что а) линукс был реализован под интел, б) 99.9% экспертов ничего кроме интела в глаза не видели. Сейчас, правда, появился арм, но это ничего не меняет. Всё это тянется с тех времён, когда их ещё не было, да и сейчас это просто игрушки.

Я же ниже разобрал это. Вам непонятно что такое прямое отображение? Либо что?

Вам непонятно что такое прямое отображение? Либо что?

Мне непонятно, зачем приплетать какой-то интел, если ни MMU не является экслюзивной разработкой интела, ни алгоритмы управления памятью в ядре не являются чем-то, присущим конкретно операционным системам для x86.

Те треды были про malloc, про него я не спорю. Но calloc же должен пройтись по всей памяти и занулить ее! Значит он маркирует ее как используемую. Так фиг там!

Мне непонятно, зачем приплетать какой-то интел, если ни MMU не является экслюзивной разработкой интела, ни алгоритмы управления памятью в ядре не являются чем-то, присущим конкретно операционным системам для x86.

Я уже ответил на этот вопрос. Об этом говорилось не в контексте процессоров, не в контексте каких-то там разработок и прочего, а в контексте представлений людей. Которые росли на этом самом х86, читали макулатуру про х86, и ничего кроме х86 не видели, да и это не особо надо.

Т.е. х86 выступал в качестве примера. Ни и никак никакое mmu не выдавалось за эксклюзивную разработку интел. Вы это сами придумали.

Всё просто. Не надо придумывать того, чего там не было.

Я как основной участник и популяризатор подобных тем — могу за них ответить.

Треды были не про маллок, а про механизмы работы памяти. Там же и было то, что и обнулять её не надо и про условия в которым это делать не надо, а именно mmap_threshold и прочее.

Но calloc же должен пройтись по всей памяти и занулить ее!

На mmap_threshold+ это не имеет смысла и это не делается.

Значит он маркирует ее как используемую.

Пройтись недостаточно — нужно именно записать. Выше я показал пример на эту тему. Где читается 100гигабайт памяти и никаких проблем это не вызывает, хотя этой памяти даже нет.

В реальном мире очень много нюансов.

И в этих темах так же говорилось, что никаких ухищрения не помогут. И каллоки обсуждались и обсуждались примеры обхода подобного поведения.

Всё было, но люди не слушали и верили в то, что у них есть какие-то свои решения.

Ну дак и какое *оффициальное* (тм) решение-то? Работает архиважная утилита на узле где 600 метров памяти, скушала она 300, а при попытке записать получит SIGSEGV. Да тот же просмотрщик фотографий на локальном компьютере — вместо открытия сверхбольших фото просто вылет ,который даже создатели просмотрщика НЕ ИМЕЮТ ВОЗМОЖНОСТИ обработать. Тупо система построена так, что аллокация памяти непроверяема. Почему сделано такое говно?

Сам лично писал код просмотрища картинок с адаптивным размером кэша предзагруженных изображений в зависимости от количества доступной памяти. А вы говорите: не имеют возможности.

Работает архиважная утилита на узле

Для архиважных утилит надо применять решения РТОС.

И переписывать под реалтайм все окружение? Нет.

А причем здесь адаптивынй кэш? Делаете malloc для отображения, система дает память, пытаетесь заполнить данными от изображения — а там сегфолт. Повторю, почему сделано такое говно, которое нельзя проверить? Почему та же сраная шиндовс имеет аллокатор памяти, который может нормально сказать, что памяти нет.

Нетъ. Куча может выделяться с говном, если аллокатор переиспользует страницы, заюзанные ранее. А если ты просишь огромный зануленный сплошной блок, то единственный разумный подход — шарахнуть анонимный mmap и получить его от системы. Естестевенно в виртуальном состоянии.

Хочешь защититься от такой подлянки — записывай нули явно, memset’ом

И переписывать под реалтайм все окружение? Нет.

Выключаешь оверкоммит в системе, накатываешь патчи для PREEMPT_RT и получаешь из линуха эдакий ртос. Для настоящих ощущений код риалтаймового приложения пишешь модулем ядра

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

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

Потому что память была на момент маллока, а потом кончилась?

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

Потому что гладиолус.

Выделите гиг анонимной памяти на машине с 2-мя гигами ОЗУ, сделайте 10 раз форк и попытайтесь каждым процессом эту память записать. И где теперь ваш бог?

Можно отключить или перенастроить memkiller. Можно отобразить файл с блочного устройства. Можно выделить страницы памяти с гарантией их отображения (выше уже обсуждалось).

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

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

Оверкоммит позволяет нехило экономить память.

На чем? На том, что приложения будут рендомно отваливаться потому что они попросили 10 а им по факту дали 5 и при попытки записи в 6й блок SIGSEGV?

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

Да, а ничего, что это требует отдельного кода по ifdef на linux, bsd, windows, android и проч и проч, просто потому, что malloc без этого всратого оверкоммита всегда будет возвращать говноуказатели?

Можно отключить или перенастроить memkiller. Можно отобразить файл с блочного устройства. Можно выделить страницы памяти с гарантией их отображения (выше уже обсуждалось).

Так и что ж блджд оно по умолчанию не работает нормально? Почему для того, чтобы получить гарантированный блок памяти надо попердолиться?

Ну дак и какое *оффициальное* (тм) решение-то?

Надо понять суть проблемы. Вернее проблемы-то и нет на самом деле. Всё это( про механизмы работы памяти) уже десять раз разжевано.

Тупо система построена так, что аллокация памяти непроверяема.

Правильно, не система, а то апи, что даёт тебе libc. А почему? Потому что это апи из 70годов. Естественно оно никак не учитывает нюансы текущей реальности.

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


Именно поэтому и сделано такое говно, только ты его не там ищешь. Говно не память — говно предоставляемые тебе интерфейсы.

Если ты хочешь 100% получить память — ты можешь её получить mmap + map_populate. Я выше уже отвечал эдику. Тогда ты 100% получишь память, либо ошибку, если памяти не хватает.

Правильно, не система, а то апи, что даёт тебе libc. А почему? Потому что это апи из 70годов. Естественно оно никак не учитывает нюансы текущей реальности.

Люльку на libc не гоните, а? У libc все правильно сделано:

Если ты хочешь 100% получить память — ты можешь её получить mmap + map_populate. Я выше уже отвечал эдику. Тогда ты 100% получишь память, либо ошибку, если памяти не хватает

Забавно, что под все остальные системы я просто могу использовать стандартный и простой в использовании malloc из libc, а для линукса нужно пердолиться для того, чтобы получить память. А полтом мне рассказывают, что malloc говно.

Так и что ж блджд оно по умолчанию не работает нормально?

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

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

Потому, что если бы память работала по образу представлений адептов libc — ты бы до сих пор сидел на калькуляторе и играл бы в прыгающий круг.

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

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

Linux — это не ОСРВ. У ней другая ниша и другие требования к разумному поведению в той непредсказуемой среде, где её запустят. Для системы общего назначения, применяемой в основном на серверах и иногда на рабочих станциях, эти умолчательные настройки оптимальны.

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

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

Если какая-то программа не соблюдает интерфейсы — то это проблемы конкретного разработчика. Если она написал a = malloc(1000); a[5] = 34 без проверки на NULL — то это сугубо его проблемы. А вы таким говнокодеров поощряете, вместо того, чтобы дать по рукам!

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

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

Люлька на libc не гоните, а? У libc все правильно сделано:

Нет, так это не работает.

Что сделали в ядре? Правильно, сказали нехер и стали всегда возвращать указатель на память, даже если ее нет.

Всё правильно сделали — убогий интерфейс из либ не в силах вместить в себя нюансы работы памяти.

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

Сомневаюсь. Скорее тебя просто обманули с кастылём, который ты можешь врубить и в линуксе.

А т.к. ты не понимаешь того — что именно ты там тестируешь — ты и тестируешь не то, что нужно. sysctl vm.overcommit_memory=2 -w и у тебя отвалиться этот говнотест, но это ничего не меняет. Это не спасёт тебя от более сложных кейсов. Как и в других ОС.

Это типичная проблема, когда ты пытаешься желаемое выдать за действительное. Ты поверил в то, что всё нормально и тебе нормально. А то, что это нихрена не работает так, как ты ожидаешь — тебе и насрать.

А полтом мне рассказывают, что malloc говно.

Рассказывают те, кто что-то в теме понимают. А неадекватная реакция неосиляторов — мало кого волнует.

Даже хрен с математикой, krita, gimp, игры, kdenlive, и прочие и прочие обычные сраные десктопные приложения, которые едят много памяти- сидишь, никого не трогаешь, ХЕРАК — krita убита OOM киллером, потому что очередное поделие systemd потребовало новый блок памяти.

Если какая-то программа не соблюдает интерфейсы — то это проблемы конкретного разработчика.

Косить под Ulrich-а Drepper-а не надо, он бы глупых вопросов на ЛОРе всё равно не задавал.

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

Мало восклицательных знаков, надо больше.

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

Если ваша программа «обсчета какой-нибудь математической задачи» вышла за пределы ОЗУ, она уже ничего вам не обсчитает, потому что работа системы под интенсивным thrashing-ом замедляется даже не в разы, а на 2-3 порядка как минимум.

Вопрос надо предъявлять не ядру, а вам:

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

И почему вы не настроили систему так, чтобы она не убивала важный именно вам процесс?

В первый раз обычный realloc, с 0 до 8, второй раз с занулением. Что-то в первом варианте я не вижу нулей.

Если ваша программа «обсчета какой-нибудь математической задачи» вышла за пределы ОЗУ

В том-то и дело, что вышла не она, а другой процесс. А прибили ее, как самую жрущую.

Сишечка — не язык ассемблера. Смирись. Она работает на абстрактной машине, которая довольно косвенно связана с железом.

В том-то и дело, что вышла не она, а другой процесс. А прибили ее, как самую жрущую.

И зачем вы запустили этот «другой процесс»?

Если какая-то программа не соблюдает интерфейсы — то это проблемы конкретного разработчика. Если она написал a = malloc(1000); a[5] = 34 без проверки на NULL — то это сугубо его проблемы. А вы таким говнокодеров поощряете, вместо того, чтобы дать по рукам!

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

Люди, которые понимают то — как работает память — им не нужно проверять какие-то нулу/хренулы — для них память не рандомная херня и их преставления о памяти не ограничиваются «память бог».

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

Именно это тебе и коробит, что почему-то реальность плюёт тебе в лицо с твоим подходом и ты требуешь того, чтобы эта реальность соответствовала твоим глупым фантазиям — такого не бывает.

Ты можешь сколь угодно долго верить в том, что проверил на null и уже не говнокод, но это не так. Это падающий говнокод, который работает лишь чисто случайно. Во что бы ты там не верил — это всегда будет так. Такие дела.

Упорное нежелание ни читать, ни думать.

И почему вы не настроили систему так, чтобы она не убивала важный именно вам процесс?

Это всё другой процесс виноват!!1111

Илон Маск рекомендует:  Как разместить пункты списка горизонтально
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL