Всем привет! Я начинающий разработчик на языке Go. До этого у меня был, так сказать, небольшой опыт, но в виде хобби. Во время изучения я также осваивал Linux, сейчас уже пользуюсь им как основной ОС.
Мой ноутбук довольно слабый, на борту всего 4ГБ ОЗУ, а на Windows существует программа, которая автоматически очищала оперативную память. Поискав в интернете, я понял, что нету такой утилиты, которая быстро и легко могла очистить оперативную память от мусора. Тогда я принялся попробовать написать ее самостоятельно.
В этой статье я расскажу, что я узнал об оперативной памяти и какими способами ее можно очистить.
Немного порыскав в интернете, я нашел информацию о кеше, который копится в оперативной памяти. Всего их два вида:
PageCache - это то место, куда ядро складывает данные, которые мы записывали/читали из диска.
inode/dentrie - сюда записывается структура файловой системы, расположение файлов и папок.
Для их очистки достаточно ввести одну команду (от суперпользователя):
sync; echo 3 > /proc/sys/vm/drop_caches
Рассмотрим, что же это значит:
sync
- синхронизирует данные на диске с данными в оперативной памяти
Запись числа 3 в /proc/sys/vm/drop_caches
- сигнал для ядра ОС, что необходимо очистить PageCache, inode и dentrie
Вот как выполнение данной команды может выглядеть в Go:
import (
"os"
"os/exec"
)
func cleanRamCache() error {
err := exec.Command("sync").Run()
if err != nil {
return err
}
err = os.WriteFile("/proc/sys/vm/drop_caches", []byte("3"), 0)
if err != nil {
return err
}
return nil
}
В данной функции мы выполнили команду sync
, а также дали ядру Linux сигнал о том, что нужно освободить кэш, записав число 3 в файл /proc/sys/vm/drop_caches
.
Далее, мы можем повысить производительность, переместив данные из Swap в оперативную память. Для этого используется данная команда (также от суперпользователя):
swapoff -a && swapon -a # Выключение и последующее включение Swap
Вызов данной команды в Go:
import "os/exec"
func restartSwap() error {
cmd := "swapoff -a && swapon -a"
err := exec.Command("bash", "-c", cmd).Run()
if err != nil {
return err
}
return nil
}
Но стоит учесть, что данное действие повысит расход оперативной памяти, так как все данные из Swap перемещаются в неё.
Также хотелось реализовать в утилите информацию об оперативной памяти. Для этого я использовал cgo
(Вызов функций C из Go):
// #include <unistd.h>
import "C"
import "fmt"
func getRam() (string, string) {
bTotal := C.sysconf(C._SC_PHYS_PAGES) * C.sysconf(C._SC_PAGE_SIZE)
gbTotal := float64(bTotal) / 1024 / 1024 / 1024
fmtTotal := fmt.Sprintf("Total: %.1f GB", gbTotal)
bFree := C.sysconf(C._SC_AVPHYS_PAGES) * C.sysconf(C._SC_PAGE_SIZE)
gbFree := float64(bFree) / 1024 / 1024 / 1024
fmtFree := fmt.Sprintf("Free: %.1f GB", gbFree)
return fmtTotal, fmtFree
}
Рассмотрим, что выполняет данная функция:
Получает информацию об объеме оперативной памяти в байтах, используя функцию sysconf
с аргументом _SC_PHYS_PAGES
(количество страниц физической памяти), переводит в гигабайты и записывает форматированную информацию в fmtTotal
Делает тоже самое для получения доступной оперативной памяти (_SC_AVPHYS_PAGES
)
Возвращает две строковые переменные с информацией об обьеме оперативной памяти и доступной памяти на данный момент
Данная утилита была бы полезна людям, которые еще не освоились в Linux, и привыкли к таким программам, как Mem Reduct в Windows. Да, это только маленькая часть того, что можно реализовать в данной программе. Но я уже немного расширил функционал программы, добавив флаги, дополнительные проверки и даже локализацию. Полный код утилиты можно посмотреть моем репозитории. Буду только рад вашим идеям по расширению функционала утилиты. Если вам понравилась эта статья, в следующей я могу описать другие части функционала программы, а также способ автоматизировать очистку. Хорошего вечера!
Линуксов много. Оформите как deb и rpm, чтобы можно было ставить
У го нет зависимостей. Клади в ~/bin и пользуй
В современном мире все ставят через менеджеры пакетов
Здорово, что Вы занимаетесь такими вещами, как написание системных утилит на Go!
Однако, очистка кеша страниц из оперативной памяти (а так же сброс свопа), как мне кажется - скорее вредный совет, эти действия могут негативно сказаться на производительности системы
Существует сайт, посвящённый объяснению того, что в Linux мы не должны бояться того, что осталось мало свободной оперативной памяти: www.linuxatemyram.com
А у меня браузер и IDE крашится, если памяти нет. :(
И свап что ли весь забивается, раз до краша доходит? Можно увеличить. Хотя я вот с 4 гигами живу вообще без него, zram хватает. Ускорения по сравнению со свапом на SSD не чувствую, скорее просто эстетически приятно, что нет лишнего IO и занятого места
простите но вы написали чушь:
"Память занята" и "память занята кешем" это сильно разные вещи. Если вся ваша ОЗУ занята каким либо софтом то она занята, и на другой софт не хватит, если же вся ваша память занята кешем то при запуске новой программы кэш моментально высвобождает столько памяти сколько требуется, и моментально здесь нисколько не для красного словца.
Конечно же это сферически и в вакууме, и бывают ситуации когда происходят какие-то проблемы, но тут ключевое слово проблемы и если у вас такая есть то скорее всего у вас проблема с железом, и принудительный дроп кэша ничем не поможет.
И еще одна крохотная ремарка - не используйте bash, там где без него "ну никак". В частности, в
restartSwap
он ну совсем лишнийВот, кстати, да, не стоит ресвопить.
Лучше кэши запихать в tmpfs или zram и их перемонтировать по мере надобности.
А эффект как-нибудь пытались измерить?
Как я понимаю - от "передергивания" свопа лучше стать не должно, мы просто загоним всё в оперативку и системе придется заново определять, что из этого скинуть на диск при недостатке оперативки. Сброс кэша - аналогично, системе придется заново считывать его содержимое с диска - оно же не зря в кэш попало?
По наблюдениям - линукс уже как лет 10-15 минимум вполне адекватно работает с памятью, если уж хочется извратиться - есть zram(fs), с которой можно во всяких позициях попробовать ;)
Будет круто, если автор сделает GUI, например на Qt.
Уже пробую:
https://github.com/arcxevodov/clnrg
Если хочется пожертвовать дисковым кэшем, чтобы программы меньше сваповались, то не обязательно делать это вручную и полностью. Можно просто единожды настроить значение swappiness поменьше, например 10. Это популярное решение для отзывчивости десктопа. На моём ноуте с 4 гигами она после этого резко улучшилась
боже мой! что я только что прочел?
От go там получается только дергание баша. Проще убрать go а bash оставить.
Отчасти да, но это ещё малая часть того, что можно реализовать)
Не слушай красноглазых троллей. Они просто программировать не умеют и поэтому гундят про свой баш. Пили лучше гуй со свистоперделками на пару гигов.
А смысл всего этого? ОС сама не справляется с очисткой и приходится за ней прибирать?
И как, начинает она после этого быстрее работать?
Ну есть же люди, закрывающие все программы на айфоне
Так они там сами закрываются, стоит отвернуться на пару минут, насколько я помню.
Впрочем, андроид тоже недалеко ушел — в телефоне 8 гигов памяти, но держать в открытом состоянии пяток вкладок в браузере в фоне он не может, видите ли…
Реально есть еще?) Я думал это осталось в лохматых 2010-х
Но если по теме, то как по мне нужен виджет в виде иконки на панель с notify сколько очищено, для понимания пользы в каждом конкретном случае, ну и лог конечно.
Это имело смысл во времена мс-дос, когда оперативы было мало. Ну и не хватает тестов, чтоб сравнить было/стало. Чуется мне, что разница будет в пределах погрешности, а может и наоборот.
Ну уж во времена DOS память чистить смысла вообще не было никакого — там не от чего её было чистить. Ну разве что резидентов лишних отключать да в верхнюю память запихивать. Но это совсем не чистка.


А так — ну вот у меня половина памяти в состоянии «ожидание».
Да, можно её «очистить». Но смысл? Если работающим программам понадобится память, то ОС сама всё сделает. Ну потратит пару микросекунд лишних в сравнении со «свободной» памятью. Но кто это заметит в повседневной жизни?
Так что, на мой взгляд, все эти чистильщики и оптимизаторы проходят по той же статье, что и «удвоители объёма ОЗУ», если кто-то помнит такие программы из девяностых.
Ну и прочие «чистильщики реестра».
Если у вас не хватает памяти, то надо её либо добавлять, либо лишние программы закрывать. А все эти очистки кэша и сбросы памяти в свап ничего не решают.
PS. Кстати, дальше можно написать программу, которая будет в /etc лишние строчки из конфигов вычищать (пустые и комментарии) для экономии места на диске. ;)
А теперь чутка документации на drop_caches (её иногда полезно читать):
А также по поводу sync перед дропом кэшей:
И что если в свопе больше чем RAM может вместить, а система пытается дропнуть весь своп обратно в память?