Re: как в С++ отследить где выделяется память
Smart-поинтеры заюзать?
Скомпилируй под Visual Studio-ей, и натрави Bounds Checker
Ну и две их у тебя.
В чем вопрос?
дело в том, что даже если в ассемблер компилять, то
из этого цикла получается кусок безо всяких call-ов , и кроме mov-ов и jmp-ов внутри куска ничего нету ,
единственное (на мой взгляд) то что может расти -- это стек, но ПОЧЕМУ?
операторами new[] она растет еще мегов на 90 в цикле?
В каком цикле-то?
сорри что не сказал.
сутки уже ебусь с этим делом
не знаю, как в Linux-е, но под Windows-ом при операции new реального выделения памяти нет, память только резервируется. Реально память начинает выделяться только при первом обращение.
Сколько памяти прога, вообще, отжирает?
ассемблерном коде этого двойного цикла
не было бы к-нибудь левого колла или джампа, который бы выделял эту память?
всеб завтра повешусь
Оптимизация...
Тебе не по фигу, как работает, если работает?
Дык это свойство не программы, а ОС.
так что левая захваченная память -- не особенно хорошо,
а если это особенности системы, кто-нибудь может что-нибудь грамотно сказать по этому поводу --
типа реально в линухе дело
-- типа это нормально, то что для выполнения цикла 3600х3600 надо жрать 90 метров памяти?
-- тем более что известно, что если тупо эту функцию написать в мэйне, то никакой такой лажи не будет, и что
вся эта лажа происходит по какой-то причине, а точнее дело в остальной программе ,
так что вопрос -- какова причина, что может вызвать такую работу программы?
разместить в оперативной памяти произвольную матрицу из 3600 x 3600 элементов по 8 байт каждый отожрав меньше 100 мегов невозможно.
видимо дело обстоит так: ты выделяешь много памяти под массивы, либся запрашивает у оси память под кучу, потом массивы ты юзаешь и память освобождаешь, но размер кучи так и остается прежним. Проверить это можно вызвав этот код несколько раз. Если памяти "утечет" все те же 200 М - то я прав, если 200М * число вызовов, то бага где-то еще
сории и спасибо всем
я все понял -- все оказалось, как и говорили --
сначала память захватывается не вся
s=3967
3967*3967*8 /1024/1024 = 120M
-- до вхождения в функцию -- 420K
-- после вызова всех new -- 35 M
-- после прогона цикла -- 139M // всего на 19 больше -- ну и забить на них
-- после вызова всех delete -- 420 K
Эх ... все я понял, еще раз спасибо за советы и сорри за непробиваемость.
Был бы ты не анонимус, получил бы 5...
Все, теперь не анонимус
правильно говорит, при маллоке реально памяти не выделяется, а ставится отображение в специальную страницу памяти с copy-on-write. Выделение физической памяти происходит при первой же операции с ней.
не надо путать HeapAlloc и malloc. Вот помнится под досом malloc работал самым нормальным образом
Оговорился. Под маллоком я понимаю выделение памяти ( средствами линукса).
т.е. под линуксом все так же, как и под виндой?
Вообще-то я писал про линукс. Насчет винды не уверен, но скорее всего так же. Там ведь есть copy-on-write ?
вообще-то copy-on-write не имеет отношения к обсуждаемому вопросу
да, возможна реализация и без него
К calloc'у точно имеет. А malloc обходится без него ?
смотря как библиотеку соберешь... там есть такой препроцессорный макрос (или переменная ) WINHEAP, если ее не объявлять, то куча реализовывается ручками, а не через CreateHeap/HeapAlloc. Вообще, copy-on-write (точнее, прерывание при обращении к определенным адресам) - это скорее фича процессора и осей которые на нем крутятся. Она может быть, а может не быть (или не использоваться стандартной библиотекой С++)
но в твоём случае, похоже, это скорее означает "каша в голове"
поясни, что и при какой записи нужно копировать и как это связано с описанным поведением?
значит это вот что: когда одна и та же DLL грузится в разные процессы, она размещается в одной и той же физической памяти, но как только меняется состояние этой DLL (например, меняется глобальная переменная аллоцируется блок в физической памяти и туда все копируется. К alloc'ам это конечно отношения не имеет, то механизм в них похожий
Я говорил про реализацию calloc, который инициализирует выделенную память нулями (казалось бы). Вместо этого он ставит отображение в некую специальную страницу памяти, забитую нулями, так что для чтения все ок. При записи происходит копирование.
Сорцов по этому поводу не читал, так что могу заблуждаться.
А и не нужно заглядывать, достаточно посмотреть, что оттуда само выходит
> При записи происходит копирование.
Реализация жизнеспособная, но надуманная, так как заполнить страницу нулями эффективнее просто записав туда нули (странно, да? а вовсе не скопировав их откуда-то ещё
Ты слишком высокого мнения о malloc. COW работает только на уровне страниц, и вообще это идиотизм тратить прерывание на копирование области размер, которой может быть 1 байт.
При выделении памяти используется другой механизм. Когда malloc понимает, что в куче места нет, он пытается расширить адресное пространство процесса (раньше для этого использовался системный вызов brk(2 который в современных системах скорее всего считается устаревшим). При этом вновь выделенные страницы не отображается ни в ОЗУ ни в swap, а просто помечаются как выделенные, но ещё не использованные. Фактическое отображение этих страниц происходит при первом обращении. Таким образом память действительно не выделяется до момента фактического обращения. При этом прерывание вызывается не для каждого байта, а для каждой страницы.
Напиши простую программу, вызывающую calloc и убедись, что память выделяется не сразу (что имело бы место, если бы она просто заполнялась нулями а по мере использования.
Наличие применения copy-on-write это не докажет
Ничто не мешает выделять страницу и заполнять её нулями по факту возникновения исключения при записи (либо вообще брать её из пула заранее занулённых, если есть возможность такой пул поддерживать).
Суть моей претензии в том, что COW не исчерпывает набор техник, используемый подсистемой виртуальной памяти, хотя и называется красиво.
В частности, в данном случае он не используется, и вовсе не случайно, а потому, что просто не имеет отношения к этой задаче.
А по твоим постам создаётся впечатление, что ты выучил красивое слово, но не его значение. Успокойся и попробуй систематизироваить свои знания, и всё получится.
Это надо повесить в рамочке над столом...
Точно! Поверх этого дурацкого стеклянного экрана.
Поверх портрета научника
как это не назавайте, а все равно -- один хуй --
память выделяется при первом обращении к области данных
на этом, на мой взгляд и следует завершить дискуссию, а не переливать из пустого в порожнее.
я на свой вопрос получил ответ, а если у кого остались вопросы -- делайте новый тред.
ну или голование устройте -- кто типа самый клевый программер
Один человек, которого я весьма уважаю как программиста, когда-то сказал мне это, и я не удосужился проверить.
Однако.
Посмотрим в код glibc. calloc реализуется как malloc и mmap(/dev/zero).
Посмотрим в код ядра, а именно drivers/char/mem.c, там реализован /dev/zero. Грепни его, например, по слову "COW". Посмотри, например, функцию do_wp_page (Шурик, спасибо, без тебя я бы на это полдня потратил! ).
Теперь глубоко вдохни и попробуй ответить без эмоций и ненужной распальцовки.
неверное утверждение. Верное - физическая память может выделиться при первом обращении. А может и не выделиться, если уже выделена.
подколол
Приведи, пожалуйста, man по calloc здесь.
NAME
calloc, malloc, free, realloc - Allocate and free dynamic memory
SYNOPSIS
#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);
void *malloc(size_t size);
void free(void *ptr);
void *realloc(void *ptr, size_t size);
DESCRIPTION
calloc allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the
allocated memory. The memory is set to zero.
malloc allocates size bytes and returns a pointer to the allocated memory. The memory is not cleared.
free frees the memory space pointed to by ptr, which must have been returned by a previous call to mal-
loc calloc or realloc. Otherwise, or if free(ptr) has already been called before, undefined
behaviour occurs. If ptr is NULL, no operation is performed.
realloc changes the size of the memory block pointed to by ptr to size bytes. The contents will be
unchanged to the minimum of the old and new sizes; newly allocated memory will be uninitialized. If ptr
is NULL, the call is equivalent to malloc(size); if size is equal to zero, the call is equivalent to
free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc calloc or
realloc.
RETURN VALUE
For calloc and malloc the value returned is a pointer to the allocated memory, which is suitably
aligned for any kind of variable, or NULL if the request fails.
free returns no value.
realloc returns a pointer to the newly allocated memory, which is suitably aligned for any kind of vari-
able and may be different from ptr, or NULL if the request fails. If size was equal to 0, either NULL or a
pointer suitable to be passed to free is returned. If realloc fails the original block is left
untouched - it is not freed or moved.
CONFORMING TO
ANSI-C
SEE ALSO
brk(2 posix_memalign(3)
NOTES
The Unix98 standard requires malloc calloc and realloc to set errno to ENOMEM upon failure. Glibc
assumes that this is done (and the glibc versions of these routines do this); if you use a private malloc
implementation that does not set errno, then certain library routines may fail without having a reason in
errno.
Crashes in malloc free or realloc are almost always related to heap corruption, such as overflowing
an allocated chunk or freeing the same pointer twice.
Recent versions of Linux libc (later than 5.4.23) and GNU libc (2.x) include a malloc implementation which
is tunable via environment variables. When MALLOC_CHECK_ is set, a special (less efficient) implementa-
tion is used which is designed to be tolerant against simple errors, such as double calls of free with
the same argument, or overruns of a single byte (off-by-one bugs). Not all such errors can be protected
against, however, and memory leaks can result. If MALLOC_CHECK_ is set to 0, any detected heap corruption
is silently ignored; if set to 1, a diagnostic is printed on stderr; if set to 2, abort is called imme-
diately. This can be useful because otherwise a crash may happen much later, and the true cause for the
problem is then very hard to track down.
Linux follows an optimistic memory allocation strategy. This means that when malloc returns non-NULL
there is no guarantee that the memory really is available. In case it turns out that the system is out of
memory, one or more processes will be killed by the infamous OOM killer.
GNU 1993-04-04 MALLOC(3)
Мнда. Ничего конретного. Не мог бы ты запостить еще реализацию calloc, если она небольшая, или хотя бы вызовы malloc и mmap оттуда. Я никак не могу понять, зачем ему вызывать их одновременно. Чтобы выделить память достаточно mmap.
ftp://kai.local/pub/temp/malloc.c - это из glibc-2.3.2
Судя по комментариям, mmap делается для достаточно больших кусков памяти, начиная с 1Мб. Иначе - sbrk. Вроде так.
Ну тогда понятно. calloc выделяет очень большие запросы через mmap и число таких запросов ограничено. Маленькие куски памяти зануляются вручную в calloc, большие зануляются автоматически по требованию. Т.е. все логично и понятно - при выделении небольших участков памяти никакого Copy on write не производится, не считая случая, когда куча разрослась и вылезла за свои прежние границы. И даже в этом случае этот COW 1) не имеет значения и 2) произойдет при выделении памяти, а не потом, когда пользователь будет писать. Когда выделяется большой кусок памяти, то используется mmap, а это значит, что указатель будет выровнен по размеру страницы и будет выделено количество памяти кратное размеру страницы (если не кратно, то округлят). После этого, если в не присутствующую в памяти страницу из этой области ты попытаешься что-нибудь записать, то произойдет прерывание, эта страница будет выделена и заполнена нулями. Кстати, /dev/zero звучит гордо, но по сути любая страница выделенная процессу будет перезаписана нулями, иначе было бы не секьюрно.
Объясни пункт 2.
2 - участки памяти, выделенные без mmap, зануляются в calloc. Поэтому даже если физическая память не была выделена, она будет выделена при занулении.
А, понял, это относилось к маленьким кускам памяти.
#include <stdlib.h>
main {
void *p = calloc(6000, 1000);
sleep(10);
free(p);
p = calloc(3000, 1000);
sleep(10);
free(p);
}
показывает два равнозначных mmap'а.
Какие же они равнозначные? Один на 6 мегов, а другой на 3.
Если бы оба были на 6, я бы сказал "одинаковые". А так - равнозначные
Тогда я не понял, что ты хотел сказать
Оставить комментарий
max87544
Проблема в следующем :Есть в проге функция : //она конечно не такая, но с этой тоже самое.
double **dists1;
double **dists2;
long i1,j1,s=scheme.size;
dists1= new (double*)[s+1];
dists2= new (double*)[s+1];
for (long it=0;it!=s+1;it++)
dists1[it]= new double[s+1];
for (long it=0;it!=s+1;it++)
dists2[it]= new double[s+1];
for (i1=0;i1!=s;i1++)
{
for (j1=0;j1!=s;j1++)
{
dists1[1][1]=dists1[i1][j1]=2.;
}
}
for (long it=0;it!=s+1;it++)
delete [](dists1[it]);
delete []dists1;
for (long it=0;it!=s+1;it++)
delete [](dists2[it]);
delete []dists2;
// прогонялось при s == 3600
// прога под линух
// linux-2.4.22-ac2
// gcc version 3.3.1 20030903 (Red Hat Linux 3.3.1-3)
Так вот, в процессе ее выполнении прогой отжирается память -- порядка 200 мегов, причем память отжирается не сразу, а постепенно, в процессе выполнения цикла.
Как компилировать - пофиг , что с O4 что с O0 что с --no-inline -- без разницы -- все равно память жрет.
с gdb тоже ничего хорошего не вышло -- память отжирается нерегулярно, и при прогонке по шагам я задолбался ждать, пока память выделится,
так что может быть уто и посоветует как с помощью gdb это отловить?
Если кто знает и возможно сталкивался -- в чем проблема, почему так происходит,
заранее спасибо за ответы