LINUX.ORG.RU

Разбухание памяти в программах на C/C++ в Linux


0

0

Я на днях прочитал, что реализация функций malloc и free в glibc не выполняет никакой работы по сокращению объёма используемой памяти, не считая системного вызова brk() или как там его, в результате чего получается фрагментация используемой программой оперативной памяти.

Интересно стало, как с этим можно бороться и как вообще люди борются?

Кстати, прошёл слушок, что возможно заюзать реализацию malloc из openbsd, неужели правда?

P.S. Вопрос навеян тенденцией всё большего и большего пожирания памяти линуксовыми програмами, например, firefox, потребление памяти которым просто легендой стало.

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

Мысли вслух: чегой-то тема в Talks не поимела конструктивного продолжения.

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

А вот и не ура. В этом тоже выдаёт ту же ошибку:

misc/prnetdb.c:1192: error: conflicting types for `getprotobyname_r'

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

Делаю ./configure --enable-trace-malloc --enable-application=browser, затем запускаю gmake, вскоре вываливается с этой ошибкой. В гугле ответа не нашёл, мало что там есть по поводу "conflicting types for `getprotobyname_r'".

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

Этот?
$ cat ~/.mozconfig
# sh
# Build configuration script
#
# See http://www.mozilla.org/build/unix.html for build instructions.
#

# Options for client.mk.
mk_add_options MOZ_CO_PROJECT=browser
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-@CONFIG_GUESS@

# Options for 'configure' (same as command-line options).
ac_add_options --enable-application=browser
ac_add_options --enable-trace-malloc

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

Ну что, опять тупик?

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

Для firefox надо так:

export MOZ_PHOENIX=1 mk_add_options MOZ_PHOENIX=1

# Options for client.mk. mk_add_options MOZ_CO_PROJECT=browser mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-@CONFIG_GUESS@

# Options for 'configure' (same as command-line options).

ac_add_options --prefix=/path/to/installation

ac_add_options --enable-application=browser

ac_add_option --enable-trace-malloc ac_add_option --enable-debug

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

mr, в openbsd firefox собирается через порт:
http://www.openbsd.org/cgi-bin/cvsweb/ports/www/mozilla-firefox/

Makefile cодержит инструкции по сборке порта.

чтобы установить порты, необходимо взять ports.tar.gz от установленной
версии openbsd и распаковать в /usr:

  # cd /usr && tar xzf ~/ports.tar.gz

чтобы обновить порты до -stable:

  # cd /usr/ports
  # cvs -z3 -fqd anoncvs@anoncvs.ca.openbsd.org:/cvs up -PAdrOPENBSD_3_8 .

порт устанавливается так:

  # cd /usr/ports/www/mozilla-firefox
  # make install clean CLEANDEPENDS=Yes

можно собрать только пакадж например:

  # make package

в общем -- man ports, man bsd.port.mk

чтобы добавить опции сборки, необходимо отредактировать строку
с CONFIGURE_FLAGS.

cu.

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

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

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

Из портов собирай, выше правильно говорят. Ты BSD что ли никогда не видел?

В OpenBSD патчей на этот distfile накладывается несколько десятков.

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

Убедись сначала, что умолчальная сборка из ports работает. Потом можно экспериментировать с --enable-debug --enable-trace-malloc

-- тот анонимус

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

Понятно. Да, с BSD столкнулся в первый раз.

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

yep.

положи firefox-....tar.gz, который ты скачал с chg.ru в
/usr/ports/distfiles, а то он перекачивать будет.

и посмотри с каким gtk собирается. (там с 2.x кажись)

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

> что, прийдётся всё снова перекомпилировать ??

лучше перекомпилировать во избежание.

То есть сначала make distclean && ./configure && make

как в openbsd это делается, уточни.

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

Сделал так, а он (make package) говорит, что checksum не сходится :( Прийдётся перекачивать.

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

Ну вот, поставил я его компилится (версия 1.0.8, более новая не скомпилилась). Пока что не вылетел, так что есть шанс. Только в тормозной openbsd всё это, чувствую, будет очень долго происходить...

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

хе-хе, дык C++ ;)

в -current портах есть последний. для того, чтобы поставить -current
порты:

 # cd /usr/ports
 # cvs -z3 -fqd anoncvs@anoncvs.ca.openbsd.org:/cvs up -PAd .

установить pkg_* от -current:

 # cd /usr/src/usr.sbin/pkg_add
 # cvs -z3 -fqd anoncvs@anoncvs.ca.openbsd.org:/cvs up -PAd .
 # make obj
 # make depend
 # make
 # make install

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

> в -current портах есть последний.

не надо -current.

Подождем, достаточно поиметь proof of concept в виде сравнения вывода malloc_stats() под OpenBSD и Linux.

-- другой анонимус

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

firefox 1.5.0.1 я пытался установить так:

# cd /usr/ports/www/mozilla-firefox
# cvs -z3 -fqd anoncvs@anoncvs.ca.openbsd.org:/cvs up -PAdrOPENBSD_3_9 .
# make install clean CLEANDEPENDS=Yes

Оно мне выдало, что есть зависимость от cairo, а этой самой cairo в текущих пакетах нет (а пакеты openbsd 3.9 ещё не появились).

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

Так, а где должен быть вывод malloc_stats()? Что-то в выводе я его не вижу (запускал просто командой firefox&).

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

Что-то не появляется. Слушай, а почему ты решил, что в openbsd есть функция malloc_stats()?

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

похоже, через trace-malloc malloc_stats() она не выводит.

mr, если не очень устал еще, в nsprpub/pr/src/malloc/prmem.c вставь malloc_stats() прямо в PR_Free():

PR_IMPLEMENT(void) PR_Free(void *ptr)
{
fprintf(stderr,"DEBUG:PR_Free:"); malloc_stats();
if (use_zone_allocator)
pr_ZoneFree(ptr);
else
free(ptr);
}

Для bugzilla так делал.

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

в openbsd можно использовать "опции malloc":
 http://www.openbsd.org/cgi-bin/man.cgi?query=malloc&sektion=3

 % export MALLOC_OPTIONS=D
 % firefox &

надо только пересобрать libc с -DMALLOC_STATS.
ну или в файле /usr/src/lib/libc/stdlib/malloc.c:

заменить:

#ifndef MALLOC_STATS
#undef  MALLOC_STATS
#endif

на:

#defined MALLOC_STATS

и пересобрать libc:

 # cd /usr/src/lib/libc
 # make obj
 # make depend
 # make
 # make install

(не сильно долгий процесс..)

cu.

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

Из man malloc:

Malloc will first look for a symbolic link called /etc/malloc.conf and
next check the environment for a variable called MALLOC_OPTIONS and fi-
nally for the global variable malloc_options and scan them for flags in
that order. Flags are single letters, uppercase means on, lowercase
means off.

A ``Abort''. malloc() will coredump the process, rather than tol-
erate failure. This is a very handy debugging aid, since the
core file will represent the time of failure, rather than when
the null pointer was accessed.

D ``Dump''. malloc() will dump statistics in a file called
malloc.out at exit. This option requires the library to have
been compiled with -DMALLOC_STATS in order to have any effect.
Так, как это расшифровать?

>man malloc_dump посмотри, возможно, она так называется
$ locate malloc|grep man
/usr/share/man/cat3/malloc.0
/usr/share/man/cat5/malloc.conf.0
/usr/share/man/cat9/malloc.0
/usr/share/man/cat9/uvm_km_kmemalloc.0

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

> man malloc_dump

просто man malloc, где говорится о переменной MALLOC_STATS. Для этого надо собрать libc с -DMALLOC_STATS, см, пост предыдущего автора.

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

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

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

> как её безопасно установить тоже непонятно.

LD_PRELOAD там есть?

> Так, в портах нету, где брать не понятно,

Погоди, "ишшы, должон быть" (c) :)

Минуту.

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

> Постелька зовёт меня :(

Господа гусары, папрашу промолчать-с (c) :)

У меня сейчас дерево /usr/src checkout'ится, завтра посмотрим.

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

Я скопировал malloc.c и thread_private.h, компилирую gcc -DMALLOC_STATS -shared -fpic malloc.c -o malloc.so (когда без -DMALLOC_STATS файл .so другой)

Когда запускаю с LD_PRELOAD=./malloc.so ls всё нормально, когда с MALLOC_OPTIONS=D LD_PRELOAD=./malloc.so ls выводит сообщение: ls in malloc(): warning: unknown char in MALLOC_OPTIONS

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

Так вот почему не работает: LD_PRELOAD=./malloc.so не действует!

Заменил в malloc.c строку

wrtwarning("unknown char in MALLOC_OPTIONS");

на

wrtwarning("unknown hop! hop! char in MALLOC_OPTIONS");

скомпилил в .so: на выводе всё те же

unknown char in MALLOC_OPTIONS

Как это объясните, господа?

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

Да, firefox не ругается на это, вот вывод после установки соотв. LD_PRELOAD и MALLOC_OPTIONS:
$ firefox& 
[1] 17421
sh in malloc(): warning: unknown char in MALLOC_OPTIONS
$ malloc() warning: hop! hop! Couldn't dump stats
malloc() warning: hop! hop! Couldn't dump stats
pwd in malloc(): warning: unknown char in MALLOC_OPTIONS
expr in malloc(): warning: unknown char in MALLOC_OPTIONS
malloc() warning: hop! hop! Couldn't dump stats
malloc() warning: hop! hop! Couldn't dump stats
sh in malloc(): warning: unknown char in MALLOC_OPTIONS
malloc() warning: hop! hop! Couldn't dump stats
malloc() warning: hop! hop! Couldn't dump stats

Где hop! hop! -- это опять я добавил.

Вот место из malloc.c с Couldn't:

#ifdef MALLOC_STATS
static void
malloc_exit(void)
{
        char    *q = "malloc() warning: hop! hop! Couldn't dump stats\n";
        int     save_errno = errno, fd;
 
        fd = open("malloc.out", O_RDWR|O_APPEND);
        if (fd != -1) {
                malloc_dump(fd);
                close(fd);  
        } else
                write(STDERR_FILENO, q, strlen(q));
        errno = save_errno;
}
#endif /* MALLOC_STATS */

Теперь надо понять, почему он не хочет открывать malloc.out.

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

Переправил я поток на stderr, заменив fd=... на fd = open("/dev/stderr", O_RDWR|O_APPEND);

При запуске и закрытии firefox получаю кучу сообщений типа:

8b09b000 569499 0x7ca48060 0 (of 8) x 512 @ 0x8ac93000 --> 0x0
8b09c000 569500 .. 569883 not mine
8b21c000 569884 0x88b790e0 0 (of 8) x 512 @ 0x8ae14000 --> 0x0
8b21d000 569885 .. 570179 not mine
8bb3c000 572220 .. 572824 not mine
8bd99000 572825 .. 572825 in use
8bd9a000 572826 .. 572917 not mine

Которая заканчивается чем-то типа:

Minsize 16
Maxsize 2048
Pagesize        4096
Pageshift       12
In use  16384
Guarded 0

Как это относится к нашим целям непонятно. Похоже прокольчик вышел?

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

> почему он не хочет открывать malloc.out.

т.к. O_RDWR|O_APPEND, malloc.out должен существовать до open()

touch ./malloc.out :)

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

> Как это относится к нашим целям непонятно. Похоже прокольчик вышел?

Нет прокола. Задачка решена уже в принципе.

Осталось научится прочесть из дампа кол-во mallocнутого, и количество mmapнутого. Если (mallocнутое)/(mmapнутое) в openbsd > (total in use bytes)/(total system bytes) в таком же сеансе под linux, то эффект от mmap-ного malloc четкий.

Сравнивать с https://bugzilla.mozilla.org/show_bug.cgi?id=324081#c17

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

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

Честно говоря, я пока не понял, что там вообще в дампе выводится. Но на количество malloc'ов это не похоже (вроде их должно быть гораздо больше, чем ~1000 строк в malloc.out). Хотя может что и получится.

P.S. Про touch ./malloc.out верно подмечено. Кстати, вас двое (анонимусов) или один? :)

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

> Кстати, вас двое (анонимусов) или один? :)

анонимус един в многих лицах (c) :)))

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

> Но на количество malloc'ов это не похоже

там не кол-во вызовов malloc/free надо, a сколько байт они запросили-освободили (1) . И сравнить, сколько байт в то же время mmapнуто (2).

В одинаковом сеансе отношение (1)/(2) должно быть больше, чем (used bytes)/(system bytes) из вывода malloc_stats() в linux.

Например, после закрытия всех табов в твоем примере выше в openbsd (1)/(2) ~ 10M/20M (VM упало до ~40M c 60M), а в linux (used bytes)/(system bytes) ~ 10M/40M, т.к. там отожранные 60М не возвращаются ядру.

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

Да не, я про то, как извлечь эту информацию...

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

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

Типа в openbsd3.8 сразу после запуска с пустой страницей фаер отжирает 25M (ил 29M с каким-нибудь небольшим сайтиком). После нескольких часов активной работы и массы открытых окон и табов объём достигает 90M. После закрытия всех окон и табов, кроме одного пустого, объём уменьшается до 56M.

На английский перевести и опубликовать ?

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

Опубликовать... Как красиво звучит.

Только надо открывать ~30 табов с bbc для соответствия с той темой из bugzilla.

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

Вывод ps vp `pidof firefox-bin` в openbsd и linux сравнивать напрямую нельзя. Для bugzilla нужна статистика самогО аллокатора по динамической памяти.

С malloc_dump() сегодня не успеваю. Разберусь после разгреба работы.

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

------- Comment #25 From Boris Zbarsky 2004-09-21 22:50 PDT [reply] -------

The point is, we don't want to be in the business of rewriting the OS allocators...

Они всегда так говорят (вот был, например, баг в gtk с фокусом в некоторых wm--они даже не пошевелились, чтобы исправить, так ведь в конце концов его сотрудники РедХат исправили). Вряд ли мозилловцы будут что-то предпринимать в этом направлении.

С таки запросами можно сразу к маинтайнерам glibc идти. Хотя и те могут сказать то же самое. Самим что ли пытаться переписать этот аллокатор?

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

> The point is, we don't want to be in the business of rewriting the OS allocators...

Следующий пост, по памяти : " .. memory management is not the most complicated part of the system mozilla successfully replaces ... "

В glibc не нужно, ее аллокатором большинство программ довольно.

Не можешь огранизовать доступ к OpenBSD по ssh для одного IP? так дело пойдет быстрее.

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

>Не можешь огранизовать доступ к OpenBSD по ssh для одного IP? так дело пойдет быстрее.

Не, чё-то не знаю, как это сделать. Он из под локального ip впускает (с 192.168.x.x), а из-под внешнего нет. Может настроить sshd как-то надо, не знаешь как?

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

Afaiu, настраивается не сам sshd, а аналог линуксового tcpd.

См. /etc/hosts.allow, /etc/hosts.deny.

В hosts.deny там вероятно ALL: ALL, в hosts.allow надо вписать что-то вроде in.sshd: <внешний адрес> .

man hosts.allow ?

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

Не, в hosts.deny и в hosts.allow ничего нет.

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

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

>Типа может мой провайдер предоставляет мне доступ в интернет через какой-нибудь маскарадинг?

А вообще знаешь, видимо так и есть, потому что "... password" откликается даже когда у меня sshd выключен. Что же тогда делать?

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

Да, есть, 334-911-008.

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