1
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
11
<meta content="text/html; charset=UTF-8" http-equiv="content-type"><title>index-alloc.html</title></head><body>
15
<div style="text-align: center;">
16
<h4>Про выделение динамической памяти, или почему firefox так много
17
памяти потребляет.</h4>
25
(Последний раз обновлено 24 августа 2006 года).<br>
29
Всё началось с того, что все заметили, как много оперативной памяти
30
кушает firefox. А также то, что он не возвращает её системе после
31
закрытия всех открытых web-страниц.<br>
39
Например, здесь с помощью функции malloc_stats() показано, что это не
40
утечки памяти: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=324081#c17">https://bugzilla.mozilla.org/show_bug.cgi?id=324081#c17</a>.
41
А здесь это показано с помощью некой "leak-gauge tool"<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=324081#c9">
42
https://bugzilla.mozilla.org/show_bug.cgi?id=324081#c9</a>.<br>
50
Оказывается, что реализация malloc в glibc выделяет память в куче с
52
brk/sbrk, т.е. одним большим связным куском. Эта куча может уменьшаться
53
только с конца, освободить память в середине невозможно (не считая
54
вызова madvise). Так что даже один байт в конце кучи не позволяет
55
отдать память системе. И malloc размещает переменные
56
в памяти по сути просто друг за другом. Это создаёт условия для такого
57
явления, как <span style="font-style: italic;">фрагментация памяти</span>.<br>
63
Существенно улучшить положение может аллокатор, основанный на mmap
64
(mmap--вызов, выделяющий память отдельной областью, пропорционально
65
размеру страницы, 4096 байт) и на соответствующих алгоритмах размещения
66
переменных в памяти. <br>
68
Можно использовать довольно простой аллокатор из
69
OpenBSD-libc. Вообще-то, он был создан для другой цели, обеспечения
70
безопасности -- защиты от ошибки переполнения буфера<span style="font-weight: bold;"></span>...
71
но пришлось использовать его по причине отсутствия "навороченного"
72
mmap-based аллокатора. <span style="font-weight: bold;"></span>Предварительная версия для ОС Linux может быть найдена <a href="http://mr.himki.net/OpenBSD_malloc_Linux.c">здесь</a> в виде готового файла (и <a href="http://mr.himki.net/OpenBSD_malloc.patch">здесь</a>
73
в виде патча к версии 1.83 из cvs). Собирать так: gcc -shared -fPIC
74
-O2 OpenBSD_malloc_Linux.c -o malloc.so, запускать так:
75
LD_PRELOAD=/path/to/malloc.so firefox.<span style="font-weight: bold;"><br>
77
</span>Этот аллокатор можно использовать и с другими программами, но не
78
со всеми работает (например, с emacs не работал, а также, говорят, с
79
некоторыми сборками KDE). Но firefox почти у всех (и у меня всегда)
84
В общем, ищется программист, который бы написал более навороченный (чем в OpenBSD) аллокатор.<br>
88
<span style="font-weight: bold;">Статистика аллокаций.<span style="font-weight: bold;"><br>
90
</span></span>Количество аллокаций определённого числа байт показана <a href="http://mr.himki.net/conv-alloc-dat">здесь</a>.<br>
92
А <a href="http://mr.himki.net/alloc-stat-old.html">вот</a> более старая информация (с картинками!).<br>
98
<span style="font-weight: bold;">Объяснение явления.</span><br>
102
<span style="font-weight: bold;">1. Почему память не возвращается?</span><br>
106
Ответ на этот вопрос очевиден--не все переменные удаляются, и некоторые
107
из них "затыкают" кучу с конца.<br>
111
<span style="font-weight: bold;">2.</span> Если закрыть все
112
web-страницы, кроме одной, а затем продолжить использовать браузер, то <span style="font-weight: bold;">почему потребление памяти снова растёт и
113
растёт неограниченно</span>--ведь в куче должно было остаться
114
достаточно места от предыдущих web-страниц?<br>
118
Из эксперимента ясно, что общий объём всех аллокаций в ~500M при 50M
119
занятой памяти. Размер аллокаций разный--есть и в 20 байт, есть и в
120
4000 байт, причём малых аллокаций во много раз больше. Таким образом,
121
если в куче появляется большая дырка, то она тут же занимается меньшими
122
по сравнению с ней кусками, в промежутках между которыми набросано
123
много совсем мелких кусков размером ~20 байт, некоторые из этих мелких
124
кусков не удалятся--а это значит, что после того, как меньшие куски
125
будут удалены, большая дырка разобъётся на несколько меньших дырок.
126
Вспомнив, что такой процесс происходит порядка 500M/50M=10 раз,
127
становится понятно, что используемая за время даже небольшого сеанса
128
превращается в кашу, т.е. в куче аллокированные куски разделены
129
небольшими промежутками, больших дырок в куче нет. А это значит, что
130
когда firefox'у понадобится аллокировать большой кусок, то в куче для
131
него не окажется достаточного промежутка, и прийдётся делать это
132
расширяя всю кучу с помощью всё той же brk/sbrk.<br>
140
Обе эти проблемы могут большей частью решены хорошим аллокатором,
141
основанным на mmap.<br>
b'\\ No newline at end of file'