Linux и zRam — экономим оперативную память

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

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

SWAP — универсальное средство?

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

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

  • Скорость доступа, чтения и записи — каким бы быстрым не был накопитель, скорость чтения/записи информации на него, а так же отклика на запрос ввода/вывода в лучшем случае в сотни раз меньше аналогичных действий с оперативной памятью
  • Необходимость перезаписывать физический носитель — да, это проблема. Если на ноутбуке, использующего лишь для сёрфинга данных попадающих в подкачку не так и много, то вот на рабочих станциях, серверах и встраиваемых решениях с недостатком оперативной памяти раздел подкачки используется регулярно. А если Ваша система использует SSD-диски, вместо классических HDD, то будьте готовы к частой смене носителей.
  • Если Ваши приложения используют помимо большого количества оперативной памяти еще и интенсивно читают-пишут файлы, то всё к чертям замедлится, потому что системе надо сбросить лишнее в раздел подкачки, а приложениям выдернуть с жесткого диска файл. Борьба интересов.

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

Что такое zRam

Не буду углубляться глубоко в теорию, расскажу, как говорится, на пальцах.
Модуль ядра zRam в системах семейства Linux создает виртуальное блочное устройство, что-то вроде жесткого диска, который размещается в оперативной памяти. С ним можно делать что угодно, форматировать, монтировать и так далее. Вот только в отличии от других виртуальных блочных устройств, все данные на ходу сжимаются при записи, а при чтении разжимаются. Причем степень сжатия по оценкам некоторых пользователей — до восьми раз.
Конечно, степень сжатия во многом зависит от типа данных, размещаемых в этом устройстве.

Что там можно разместить? Что угодно, что не жалко потерять при перезагрузке устройства. Например, временные файлы или же не важные логи.
Однако фантазия людей пошла дальше. Раз мы имеем полноценное устройство, то разместим ка мы в нем.. Раздел подкачки!
Именно тот самый swap-раздел.

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

Картина многообещающая, а главное работает. На личном опыте — устройства типа бюджетных нетбуков с 2Гб оперативной, которые используются для периодического Web-серфинга даже при двух десятках открытых вкладках в прожорливом Chromium продолжают спокойно работать, а главное жесткий диск лишний раз не дергают.

Используем zRam для размещения swap

Ну приступим от теории к практики.
Рассмотрю несколько систем семейства Linux:

zRam в Ubuntu

Ubuntu — весьма популярный дистрибутив, особенно среди начинающих линуксоидов, грех было бы её не упомянуть.
Чтобы начать использовать zRam в Ubuntu для рассматриваемого сценария достаточно установить всего лишь один пакет из официального репозитория:

sudo apt-get update
sudo apt-get install zram-config

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

~$ swapon -s
Filename	Type		Size	Used	Priority
/dev/zram0	partition	512432	176828	5
/dev/zram1	partition	512432	176536	5

zRam в Debian

Знакомый многим Debian трудится как на рабочих компьютерах, так и на серверах далеко не маленьких компаний.
В нём одной командой не обойтись, однако готовых решений на просторах интернета найти можно не мало.
Рассмотрим один из вариантов.
Создадим загрузочный скрипт

~# nano /etc/init.d/zram-swap

со следующим содержимым

#!/bin/bash
### BEGIN INIT INFO
# Provides: zram
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Increased Performance In Linux With zRam (Virtual Swap Compressed in RAM)
# Description: Adapted from systemd scripts at https://github.com/mystilleef/FedoraZram
### END INIT INFO
start() {
# get the number of CPUs
num_cpus=$(grep -c processor /proc/cpuinfo)
# if something goes wrong, assume we have 1
[ "$num_cpus" != 0 ] || num_cpus=1
# set decremented number of CPUs
last_cpu=$((num_cpus - 1))
FACTOR=40
#& put the above single line in /etc/default/zram with the value you want
[ -f /etc/default/zram ] && source /etc/default/zram || true
factor=$FACTOR # percentage
# get the amount of memory in the machine
memtotal=$(grep MemTotal /proc/meminfo | awk ' { print $2 } ')
mem_by_cpu=$(($memtotal/$num_cpus*$factor/100*1024))
# load dependency modules
echo $num_cpus
if ! modprobe zram zram_num_devices=$num_cpus
then
echo -e "Your Kernel needs to be compiled with ZRAM support:" \
"\n\nDevice Drivers --> Staging Drivers --> Compressed RAM block device support (M)" \
"\nDevice Drivers --> Staging Drivers --> Dynamic compression of swap pages and clean pagecache pages (*)"
exit 1
fi
echo "zram devices probed successfully"
# initialize the devices
for i in $(seq 0 $last_cpu); do
echo $mem_by_cpu > /sys/block/zram$i/disksize
# Creating swap filesystems
mkswap /dev/zram$i
# Switch the swaps on
swapon -p 100 /dev/zram$i
done
}
stop() {
# get the number of CPUs
num_cpus=$(grep -c processor /proc/cpuinfo)
# set decremented number of CPUs
last_cpu=$((num_cpus - 1))
# Switching off swap
for i in $(seq 0 $last_cpu); do
if [ "$(grep /dev/zram$i /proc/swaps)" != "" ]; then
swapoff /dev/zram$i
sleep 1
fi
done
sleep 1
rmmod zram
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
sleep 3
start
;;
*)
echo "Usage: $0 {start|stop|restart}"
RETVAL=1
esac
exit $RETVAL

и добавим в автозагрузку

~# update-rc.d zram-swap enable

Если не хотим перезагружаться, то запустим ручками:

~# service zram-swap start

И вновь проверяем работоспособность:

~# swapon -s
Filename	Type		Size	Used	Priority
/dev/zram0	partition	801436	0	100
/dev/zram1	partition	801436	0	100

zRam в OpenWRT

OpenWRT — операционная система семейства Linux для embedded-устройств. Например, для WiFi-маршрутизаторов или NAS-серверов. В народе её чаще именуют «альтернативная прошивка OpenWRT»
В таком роде устройств практически всегда катастрофически мало оперативной памяти, а прошивка позволяет установить и торрент-качалку и файловой сервер и еще кучу всего.
Тут то zRam опять приходит на помощь, чтобы память оперативную сэкономить:

~# opkg update
~# opkg install zram-swap

Вместо заключения

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

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

Подпишись в один клик:

Комментариев: 7

    • Проверьте /sys/block/zramX/disksize, где вместо zramX — ваши разделы, чтоб было не 0 (не ноль) — это размер разделов, он у меня по echo только через su меняет значение, а через sudo — нет (или попробовать заранее файл создавать, или попробовать sudo modprobe zram zram_num_devices=кол-во_ядер_процессора disksize=размер_создаваемого_zRAM)…
      Запуск: sudo swapon -p 5 /dev/zramX (если до этого mkswap был использован).
      И в придачу можно поменять приоритет обычного SWAP, чтоб его уже потом использовало, если не ошибаюсь:
      sudo swapoff -a
      sudo swapon -p 10 /dev/sdxX, где вместо sdxX — Ваш раздел со SWAP на жёстком.
      И снова:
      sudo swapon -p 5 /dev/zramX

        • А можете автоматический скрипт для установки zRAM применить — я написал на досуге.
          Создаёте в любом месте скрипт zram_set и запускаете его, не забыв выставить права на исполнение:
          #!/bin/bash

          # Author: Serega Kulibin

          script_path=»$0″
          script_name=$(basename «$script_path»)

          #####################
          ##### ПАРАМЕТРЫ #####
          # Пути:
          PATH_SCRIPT=’/etc/init.d/zram’ # путь к устанавливаему в автозапуск скрипту
          PATH_GET=’/bin/getpagesize’ # путь к бинарному файлу getpagesize
          ######################
          ######################

          # Заголовок:
          clear
          echo -e «\t___\033[35;1mzram_set\033[0m___\n\nЭтот скрипт включает zRAM. Дополнительно будет установлен бинарный файл команды \033[1mgetpagesize\033[0m в \»\033[34;1m$PATH_GET\033[0m\» (определяет размер страницы ОЗУ).\n»
          ############

          # Выбор ответа пользователя (y/n):
          selector_y_n()
          {
          read -s -n1 -p «Продолжить? (д/н)» symbol # ввод данных пользователем
          echo »
          if [[ «$symbol» = «N» || «$symbol» = «n» || «$symbol» = «Н» || «$symbol» = «н» ]]
          then
          check=0 # если нет — возвращаем check=0
          elif [[ «$symbol» = «Y» || «$symbol» = «y» || «$symbol» = «Д» || «$symbol» = «д» ]]
          then
          check=1 # если да — возвращаем check=1
          else
          selector_y_n
          fi
          }
          #================================#

          # Проверка параметров:
          check_string()
          {
          [ -z «$check_string» ] && check=1 || check=0 # проверяем, чтоб параметр был не пустой
          string=$(echo «$check_string» | grep ‘[^0-9]’)
          [ -n «$string» ] && check=1 # проверяем, чтоб параметр состоял только из цифр
          (( $check==0 )) && (( $check_string==0 )) && check=1 # проверяем, чтоб параметр не был равен 0 (ноль)
          }
          #====================#

          # Проверка монтирования:
          check_mount()
          {
          check=0
          if ! mount —all 2>/dev/null
          then check=1 # если ошибка — check=1, если нет ошибки — check=0
          fi
          }
          #======================#

          # Начало:
          [ «$script_name» != «zram_set» ] && echo -e «И кстати: \033[1mЗАЧЕМ ВЫ МЕНЯ ПЕРЕИМЕНОВАЛИ?!\n Вам не нравится имя \033[0m\»\033[1mzram_set\033[0m\»\033[1m?\033[0m\n»
          selector_y_n
          (( $check==0 )) && exit 0
          echo »
          #########

          # Проверка прав доступа:
          echo ‘Проверяю права доступа…’
          check_mount
          if (( $check==1 ))
          then
          echo -e «\033[31;1mНедостаточно прав доступа!\033[0m\nПопробуйте запустить \»$script_name\» с правами суперпользователя.\nКоманда запуска: \033[1msudo $script_path\033[0m»
          exit 0
          fi
          ########################

          # Проверка команд скрипта:
          echo ‘Создаю getpagesize…’
          echo -e «#include \n#include \n\nint main()\n{\n\tprintf(\»Pagesize:\\\t%d\\\tbytes\\\n\», getpagesize());\n\treturn 0;\n}\n» > /tmp/getpagesize.c # создание временного файла
          gcc -o «$PATH_GET» /tmp/getpagesize.c 1>/dev/null 2>/dev/null # установка getpagesize
          chmod 755 «$PATH_GET» # установка прав доступа (необязательная команда)
          rm /tmp/getpagesize.c 2>/dev/null # удаление временного файла

          echo ‘Проверяю команды…’
          if ! getpagesize 1>/dev/null 2>/dev/null # проверка команды getpagesize
          then
          echo -e «\033[31;1mНе найдена команда \»getpagesize\»!\033[0m»
          exit 0
          else
          check_string=$(getpagesize 2>/dev/null | cut -f2) # получение размера страницы ОЗУ в байтах
          check_string # проверка, чтоб в выводе были только цифры
          (( $check!=0 )) && echo -e «\033[31;1mНепредвиденная ошибка!» && exit 1
          pagesize_command=’PAGE_SIZE=$(getpagesize 2>/dev/null | cut -f2)’
          fi

          check_string=$(( $(grep -w ‘MemTotal’ /proc/meminfo | grep -wo ‘[0-9]*’)*1024 )) 2>/dev/null # получение размера ОЗУ в байтах
          check_string # проверка, чтоб в выводе были только цифры
          ramsize_command=»RAM_SIZE=\$(( \$(grep -w ‘MemTotal’ /proc/meminfo | grep -wo ‘[0-9]*’)*1024 )) 2>/dev/null»
          if (( $check!=0 ))
          then
          check_string=$(free -b 2>/dev/null | grep -w ‘Mem:’ | sed ‘s/[ \t][ \t]*/\t/g’ | cut -f2) # получение размера ОЗУ в байтах
          check_string # проверка, чтоб в выводе были только цифры
          (( $check!=0 )) && echo -e «\033[31;1mНепредвиденная ошибка!\033[0m» && exit 1
          ramsize_command=»RAM_SIZE=\$(free -b 2>/dev/null | grep -w ‘Mem:’ | sed ‘s/[ \t][ \t]*/\t/g’ | cut -f2)»
          fi

          check_string=$(grep -wc ‘^processor’ /proc/cpuinfo) # получение количества потоков процессора
          check_string # проверка, чтоб в выводе были только цифры
          cpunum_command=»CPU_NUM=\$(grep -wc ‘^processor’ /proc/cpuinfo)»
          if (( $check!=0 ))
          then
          check_string=$(nproc 2>/dev/null) # получение количества потоков процессора
          check_string # проверка, чтоб в выводе были только цифры
          (( $check!=0 )) && echo -e «\033[31;1mНепредвиденная ошибка!\033[0m» && exit 1
          cpunum_command=’CPU_NUM=$(nproc 2>/dev/null)’
          fi

          check_string=$(modinfo zram 2>/dev/null | grep ‘num_devices’ | cut -d ‘:’ -f2 | tr -d ‘ ‘) # проверка modinfo
          [ -z «$check_string» ] && echo -e «\033[31;1mОшибка!\033[0m Проверьте модуль \»zram\»!» && exit 1
          option_command=»OPTION=\$(modinfo zram 2>/dev/null | grep ‘num_devices’ | cut -d ‘:’ -f2 | tr -d ‘ ‘)»

          check_string=$(sysctl vm.swappiness 2>/dev/null) # проверка sysctl
          [ -z «$check_string» ] && echo -e «\033[31;1mНепредвиденная ошибка!\033[0m» && exit 1
          ##########################

          # Создание скрипта в автозапуске:
          echo -e «Создаю скрипт \»\033[35;1m$(basename $PATH_SCRIPT)\033[0m\» в \»\033[34;1m$(dirname $PATH_SCRIPT)\033[0m\»…»
          echo ‘#!/bin/sh’ > «$PATH_SCRIPT»
          echo ‘### BEGIN INIT INFO’ >> «$PATH_SCRIPT»
          echo ‘# Provides: zram’ >> «$PATH_SCRIPT»
          echo ‘# Required-Start: $local_fs’ >> «$PATH_SCRIPT»
          echo ‘# Required-Stop: $local_fs’ >> «$PATH_SCRIPT»
          echo ‘# Default-Start: S’ >> «$PATH_SCRIPT»
          echo ‘# Default-Stop: 0 1 6’ >> «$PATH_SCRIPT»
          echo ‘# Short-Description: Use compressed RAM as in-memory swap’ >> «$PATH_SCRIPT»
          echo ‘# Description: Use compressed RAM as in-memory swap’ >> «$PATH_SCRIPT»
          echo ‘### END INIT INFO’ >> «$PATH_SCRIPT»
          echo » >> «$PATH_SCRIPT»
          echo ‘# Author: Serega Kulibin ‘ >> «$PATH_SCRIPT»
          echo » >> «$PATH_SCRIPT»
          echo -e «PERCENT_ZRAM_SIZE=’40’\t# процент, занимаемый zRAM от ОЗУ» >> «$PATH_SCRIPT»
          echo -e «PERCENT_SWAP_SIZE=’50’\t# wm.swappines» >> «$PATH_SCRIPT»
          echo » >> «$PATH_SCRIPT»
          echo «$cpunum_command» >> «$PATH_SCRIPT»
          echo «$ramsize_command» >> «$PATH_SCRIPT»
          echo «$pagesize_command» >> «$PATH_SCRIPT»
          echo ‘zram_size=$(( $RAM_SIZE*$PERCENT_ZRAM_SIZE/100/$CPU_NUM/$PAGE_SIZE ))’ >> «$PATH_SCRIPT»
          echo ‘ZRAM_SIZE=$(( $zram_size*$PAGE_SIZE ))’ >> «$PATH_SCRIPT»
          echo «$option_command» >> «$PATH_SCRIPT»
          echo » >> «$PATH_SCRIPT»
          echo ‘case «$1» in’ >> «$PATH_SCRIPT»
          echo ‘»start»)’ >> «$PATH_SCRIPT»
          echo -e «\tmodprobe zram \$OPTION=\$CPU_NUM 2>/dev/null» >> «$PATH_SCRIPT»
          echo -e «\tfor i in \$(seq \»\$CPU_NUM\»)» >> «$PATH_SCRIPT»
          echo -e «\t\tdo» >> «$PATH_SCRIPT»
          echo -e «\t\t\ti=\$(( i-1 ))» >> «$PATH_SCRIPT»
          echo -e «\t\t\techo \»\$ZRAM_SIZE\» > \»/sys/block/zram\$i/disksize\»» >> «$PATH_SCRIPT»
          echo -e «\t\t\tmkswap \»/dev/zram\$i\» 2>/dev/null» >> «$PATH_SCRIPT»
          echo -e «\t\t\tswapon \»/dev/zram\$i\» -p 10 2>/dev/null» >> «$PATH_SCRIPT»
          echo -e «\tdone» >> «$PATH_SCRIPT»
          echo -e «\tsysctl -w vm.swappiness=\»\$PERCENT_SWAP_SIZE\» 2>/dev/null» >> «$PATH_SCRIPT»
          echo ‘;;’ >> «$PATH_SCRIPT»
          echo ‘»stop»)’ >> «$PATH_SCRIPT»
          echo -e «\tfor i in \$(seq \»\$CPU_NUM\»)» >> «$PATH_SCRIPT»
          echo -e «\t\tdo» >> «$PATH_SCRIPT»
          echo -e «\t\t\ti=\$(( i-1 ))» >> «$PATH_SCRIPT»
          echo -e «\t\t\tswapoff \»/dev/zram\$i\» && echo \»Disabled disk \$i of \$CPU_NUM\»» >> «$PATH_SCRIPT»
          echo -e «\tdone» >> «$PATH_SCRIPT»
          echo -e «\twait» >> «$PATH_SCRIPT»
          echo -e «\tsleep 1» >> «$PATH_SCRIPT»
          echo -e «\tmodprobe -r zram» >> «$PATH_SCRIPT»
          echo ‘;;’ >> «$PATH_SCRIPT»
          echo ‘*)’ >> «$PATH_SCRIPT»
          echo -e «\techo \»Usage: \$(basename \$0) (start | stop)\»» >> «$PATH_SCRIPT»
          echo -e «\texit 1» >> «$PATH_SCRIPT»
          echo ‘;;’ >> «$PATH_SCRIPT»
          echo ‘esac’ >> «$PATH_SCRIPT»
          echo » >> «$PATH_SCRIPT»
          chmod 755 «$PATH_SCRIPT»
          insserv zram
          echo -e «\033[32;1mOK :)\033[0m\n»
          #################################

          # Тестирование установленного скрипта:
          echo -e «Тестирование \»\033[35;1m$(basename $PATH_SCRIPT)\033[0m\» в \»\033[34;1m$(dirname $PATH_SCRIPT)\033[0m\»:»
          su -c «$PATH_SCRIPT stop» 1>/dev/null 2>/dev/null
          su -c «$PATH_SCRIPT start» 1>/dev/null 2>/dev/null
          swapon -s
          chk=0
          check_strings=$(swapon -s | grep -w ‘zram[0-9]*’ | sed ‘s/[ \t][ \t]*/\t/g’ | cut -f3) # проверка sysctl
          for check_string in $check_strings
          do
          check_string
          (( $check!=0 )) && chk=1
          done
          (( $chk==0 )) && echo -e «\033[32;1mOK :)\033[0m\n» || echo ‘Возможно нужна перезагрузка…’
          ######################################

          exit 0

Оставьте свой комментарий

Войти с помощью: