Амнезія FreeBSD

Я ніколи не розумів як працює розподіл пам'яті під FreeBSD. З усього різноманіття документації корисне пригадувалося, лише

An urban myth has circulated for years that Linux did a better job avoiding swapouts than FreeBSD, but this in fact is not true. What was actually occurring was that FreeBSD was proactively paging out unused pages in order to make room for more disk cache while Linux was keeping unused pages in core and leaving less memory available for cache and process pages.

Ну краще ніж Linux, та й нехай. Я не проти. Але гірше самого розуміючи процесу виділення пам'яті мене вбивала Inactive пам'ять. Що це таке і чи можна «це» безболісно використовувати? Вважати цю пам'ять доступною для використання додатком?

Під cut'ом більше питань ніж відповідей.

FAQ FreeBSD повідомляє, що
16.2.

Why does top show very little free memory even when I have very few programs running?

The simple answer is that free memory is wasted memory. Any memory programs that do not actively allocate is used within the FreeBSD kernel as disk cache. The values shown by top(1) labeled as Inact, Cache, and Buf are all cached data at different aging levels. This cached data means the system does not have access to a slow disk again for data it has accessed recently, thus increasing overall performance. In general, a low value shown for Free memory in top(1) is good, provided it is not very low.


Добре, нехай це кеш якогось рівня, але чому не помістити цю Inact пам'ять Cache? Може бути тому, що вона доступна для використання (як стверджують численні форумчани) і нехай не моментально, але може бути виділена за запитом?

Спробуємо з'ясувати це практичним шляхом. Маємо:
# top -b 0
last pid: 1019; load averages: 0.21, 0.45, 0.24 up 0+00:03:33 14:26:30
28 processes: 1 running, 27 sleeping

Mem: 18M Active, 17M Inact, 130M Wired, 24M Buf, 3756M Free
Swap: 3852M Total, 3852M Free

Тобто майже вся пам'ять Free і своп повністю вільний.
Тепер, щоб задіяти вільну пам'ять, створимо tmpfs розділ.

# mkdir /tmp/gb
# mount -t tmpfs -o mode=01777,size=3221225472 tmpfs /tmp/gb
# df -h | egrep "(Filesystem|tmpfs)"
Filesystem Size Used Avail Capacity Mounted on
tmpfs 3.0 G 4.0 K 3.0 G 0% /tmp/gb


При цьому
# top -b 0
last pid: 1028; load averages: 0.09, 0.19, 0.17 up 0+00:09:30 14:32:27
28 processes: 1 running, 27 sleeping

Mem: 18M Active, 17M Inact, 130M Wired, 24M Buf, 3756M Free
Swap: 3852M Total, 3852M Free

Згоден, раз розділ просто створений/примонтовано, але вільний, то нема чого виділяти йому пам'ять.
Помістимо в нього файл.
# dd if=/dev/urandom of=/tmp/gb/file.txt bs=1M count=3k
3072+0 records in
3071+0 records out
3220176896 bytes transferred in 53.334672 secs (60376801 bytes/sec)
# df -h | egrep "(Filesystem|tmpfs)"
Filesystem Size Used Avail Capacity Mounted on
tmpfs 3.0 G 3.0 G 1.0 M 100% /tmp/gb

3 гігабайти пам'яті зайнято, але при цьому
# top -b 0
last pid: 1040; load averages: 0.19, 0.26, 0.20 up 0+00:16:40 14:39:37
28 processes: 1 running, 27 sleeping

Mem: 18M Active, 3088M Inact, 137M Wired, 24M Buf, 677M Free
Swap: 3852M Total, 3852M Free

вони чомусь вважаються Inact. Але раз вона не Active, то спробуємо її задествовать. Набросаєм невеликий «Hello, world!» для виділення пам'яті і її подальшого звільнення:
#include < stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include < string.h>
int main (int argc, char *argv[])
{
int i;
char *buffer[64];
long lSize = 1024*1024*1024;
int iMB = argc < 2 ? 1 : atoi(argv[1]);
printf("iMB:\t%d\n", iMB);

for(i=0; i < iMB; i++)
{
buffer[i] = (char*) malloc (lSize);
if(buffer[i] != NULL)
{
printf("Alloc: %d\n", i);
memset(buffer[i], 127, lSize);
} else printf("Error!\n");
sleep(1);
}
sleep(10);
for(i=0; i < iMB; i++)
{
printf("Free: %d\n", i);
free (buffer[i]);
}
return 0;
}


# time ./a.out 3
iMB: 3
Alloc: 0
Alloc: 1
Alloc: 2
Free: 0
Free: 1
Free: 2
0.915 u 1.475 s 1:00.16 3.9% 5+168k 0+0io 0pf+0w

Чому так довго? Ймовірно наш tmpfs, нібито знаходиться в Inactive, видавлювався в своп.

Дійсно, при виділенні пам'яті (момент «sleep(10);» в коді) бачимо:
# top -b 0
last pid: 1128; load averages: 0.02, 0.11, 0.14 up 0+00:28:34 14:51:31
37 processes: 1 running, 36 sleeping

Mem: 3106M Active, 621M Inact, 155M Wired, 26M Cache, 27M Buf, 14M Free
Swap: 3852M Total, 2502M Used, 1350M Free, 64% Inuse

Але гірше інше. Після звільнення пам'яті додатком:
# top -b 0
last pid: 1129; load averages: 0.09, 0.12, 0.15 up 0+00:28:48 14:51:45
36 processes: 1 running, 35 sleeping

Mem: 33M Active, 621M Inact, 145M Wired, 26M Cache, 27M Buf, 3095M Free
Swap: 3852M Total, 2502M Used, 1350M Free, 64% Inuse

своп залишився задіяний.
Звернення до файлу знову повернули пам'ять Inact
# time dd of=/dev/zero if=/tmp/gb/file.txt bs=1M count=3k
3071+0 records in
3071+0 records out
3220176896 bytes transferred in 40.265654 secs (79973292 bytes/sec)
0.008 u 3.796 s 0:40.26 9.4% 22+154k 0+0io 0pf+0w
# time dd of=/dev/zero if=/tmp/gb/file.txt bs=1M count=3k
3071+0 records in
3071+0 records out
3220176896 bytes transferred in 1.242623 secs (2591434941 bytes/sec)
0.000 u 1.241 s 0:01.24 100.0% 25+173k 0+0io 0pf+0w
# top -b 0
last pid: 1144; load averages: 0.09, 0.12, 0.14 up 0+00:36:22 14:59:19
36 processes: 1 running, 35 sleeping

Mem: 29M Active, 3077M Inact, 146M Wired, 4K Cache, 27M Buf, 669M Free
Swap: 3852M Total, 2502M Used, 1350M Free, 64% Inuse

При цьому незрозуміло чому залишився Swap: 2502M Used

Але, припустимо, це нормально і при наявності вільного свопу можна вважати цю задействанную пам'ять неактивній та позначати її як Inact. Що ж буде, якщо у нас немає свопу? Сподіваюся, тепер задіяна пам'ять тепер буде Активний.
Прибираємо своп, аналогічно монтуємо 3Gb розділ tmpfs і заповнюємо його.
# top -b 0
last pid: 1013; load averages: 0.58, 0.53, 0.29 up 0+00:05:03 15:11:46
34 processes: 1 running, 33 sleeping

Mem: 21M Active, 3089M Inact, 138M Wired, 24M Buf, 673M Free
Swap:

Для очищення совісті переконаємося що top не бреше:
# expr `sysctl -n vm.stats.vm.v_inactive_count` \* `sysctl -n vm.stats.vm.v_page_size`
3239620608

І, незважаючи на відсутність свопу, наша зайнята пам'ять досі не зовсім активна… Раз вона не активна спробуємо її знову зайняти нашим додатком.
# ./a.out 3
iMB: 3
Alloc: 0
Killed

Ч. т. д. і, нарешті:
# top -b 0
last pid: 1026; load averages: 0.15, 0.22, 0.21 up 0+00:11:37 15:18:20
34 processes: 1 running, 33 sleeping

Mem: 3102M Active, 1524K Inact, 138M Wired, 200K Cache, 24M Buf, 679M Free
Swap:

# expr `sysctl -n vm.stats.vm.v_inactive_count` \* `sysctl -n vm.stats.vm.v_page_size`
1720320


Тут, напевно, повинен бути якийсь висновок, але його немає…

Джерело: Хабрахабр
  • avatar
  • 0

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.