Вступление

Всем привет! Я начинающий разработчик на языке Go. До этого у меня был, так сказать, небольшой опыт, но в виде хобби. Во время изучения я также осваивал Linux, сейчас уже пользуюсь им как основной ОС.

Мой ноутбук довольно слабый, на борту всего 4ГБ ОЗУ, а на Windows существует программа, которая автоматически очищала оперативную память. Поискав в интернете, я понял, что нету такой утилиты, которая быстро и легко могла очистить оперативную память от мусора. Тогда я принялся попробовать написать ее самостоятельно.

В этой статье я расскажу, что я узнал об оперативной памяти и какими способами ее можно очистить.

Немного о кеше оперативной памяти и пример на Go

Немного порыскав в интернете, я нашел информацию о кеше, который копится в оперативной памяти. Всего их два вида:

  1. PageCache - это то место, куда ядро складывает данные, которые мы записывали/читали из диска.

  2. 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 файла

Далее, мы можем повысить производительность, переместив данные из 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. Да, это только маленькая часть того, что можно реализовать в данной программе. Но я уже немного расширил функционал программы, добавив флаги, дополнительные проверки и даже локализацию. Полный код утилиты можно посмотреть моем репозитории. Буду только рад вашим идеям по расширению функционала утилиты. Если вам понравилась эта статья, в следующей я могу описать другие части функционала программы, а также способ автоматизировать очистку. Хорошего вечера!

Комментарии (24)


  1. WondeRu
    17.01.2023 16:09
    +1

    Линуксов много. Оформите как deb и rpm, чтобы можно было ставить


    1. rustler2000
      17.01.2023 16:33
      -5

      У го нет зависимостей. Клади в ~/bin и пользуй


      1. pfffffffffffff
        20.01.2023 09:23

        В современном мире все ставят через менеджеры пакетов


  1. prika148
    17.01.2023 16:18
    +23

    Здорово, что Вы занимаетесь такими вещами, как написание системных утилит на Go!
    Однако, очистка кеша страниц из оперативной памяти (а так же сброс свопа), как мне кажется - скорее вредный совет, эти действия могут негативно сказаться на производительности системы
    Существует сайт, посвящённый объяснению того, что в Linux мы не должны бояться того, что осталось мало свободной оперативной памяти: www.linuxatemyram.com


    1. Ryav
      17.01.2023 18:50
      -2

      А у меня браузер и IDE крашится, если памяти нет. :(


      1. Expurple
        17.01.2023 20:33
        +1

        И свап что ли весь забивается, раз до краша доходит? Можно увеличить. Хотя я вот с 4 гигами живу вообще без него, zram хватает. Ускорения по сравнению со свапом на SSD не чувствую, скорее просто эстетически приятно, что нет лишнего IO и занятого места


      1. 13werwolf13
        18.01.2023 07:07
        +2

        простите но вы написали чушь:
        "Память занята" и "память занята кешем" это сильно разные вещи. Если вся ваша ОЗУ занята каким либо софтом то она занята, и на другой софт не хватит, если же вся ваша память занята кешем то при запуске новой программы кэш моментально высвобождает столько памяти сколько требуется, и моментально здесь нисколько не для красного словца.
        Конечно же это сферически и в вакууме, и бывают ситуации когда происходят какие-то проблемы, но тут ключевое слово проблемы и если у вас такая есть то скорее всего у вас проблема с железом, и принудительный дроп кэша ничем не поможет.


  1. paramtamtam
    17.01.2023 16:31
    +2

    И еще одна крохотная ремарка - не используйте bash, там где без него "ну никак". В частности, в restartSwap он ну совсем лишний


    1. delvin-fil
      18.01.2023 05:14

      Вот, кстати, да, не стоит ресвопить.
      Лучше кэши запихать в tmpfs или zram и их перемонтировать по мере надобности.


  1. YMA
    17.01.2023 16:47
    +14

    А эффект как-нибудь пытались измерить?

    Как я понимаю - от "передергивания" свопа лучше стать не должно, мы просто загоним всё в оперативку и системе придется заново определять, что из этого скинуть на диск при недостатке оперативки. Сброс кэша - аналогично, системе придется заново считывать его содержимое с диска - оно же не зря в кэш попало?

    По наблюдениям - линукс уже как лет 10-15 минимум вполне адекватно работает с памятью, если уж хочется извратиться - есть zram(fs), с которой можно во всяких позициях попробовать ;)


  1. Writer
    17.01.2023 17:38

    Будет круто, если автор сделает GUI, например на Qt.


    1. archevodov Автор
      17.01.2023 20:49
      -2

      Уже пробую:

      https://github.com/arcxevodov/clnrg


  1. Expurple
    17.01.2023 19:53
    +8

    Если хочется пожертвовать дисковым кэшем, чтобы программы меньше сваповались, то не обязательно делать это вручную и полностью. Можно просто единожды настроить значение swappiness поменьше, например 10. Это популярное решение для отзывчивости десктопа. На моём ноуте с 4 гигами она после этого резко улучшилась


  1. FisHlaBsoMAN
    17.01.2023 21:34
    +9

    боже мой! что я только что прочел?


  1. megahertz
    17.01.2023 22:21
    +9

    От go там получается только дергание баша. Проще убрать go а bash оставить.


    1. archevodov Автор
      17.01.2023 22:27

      Отчасти да, но это ещё малая часть того, что можно реализовать)


      1. Johan_helm
        20.01.2023 11:16

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


  1. aik
    17.01.2023 22:40
    +4

    А смысл всего этого? ОС сама не справляется с очисткой и приходится за ней прибирать?
    И как, начинает она после этого быстрее работать?


    1. vvzvlad
      17.01.2023 23:22

      Ну есть же люди, закрывающие все программы на айфоне


      1. aik
        18.01.2023 06:45

        Так они там сами закрываются, стоит отвернуться на пару минут, насколько я помню.
        Впрочем, андроид тоже недалеко ушел — в телефоне 8 гигов памяти, но держать в открытом состоянии пяток вкладок в браузере в фоне он не может, видите ли…


      1. Alexzionx
        18.01.2023 08:28

        Реально есть еще?) Я думал это осталось в лохматых 2010-х

        Но если по теме, то как по мне нужен виджет в виде иконки на панель с notify сколько очищено, для понимания пользы в каждом конкретном случае, ну и лог конечно.


    1. unclegluk
      18.01.2023 02:25
      +1

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


      1. aik
        18.01.2023 06:59
        +4

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

        А так — ну вот у меня половина памяти в состоянии «ожидание».
        image

        Да, можно её «очистить». Но смысл? Если работающим программам понадобится память, то ОС сама всё сделает. Ну потратит пару микросекунд лишних в сравнении со «свободной» памятью. Но кто это заметит в повседневной жизни?

        Так что, на мой взгляд, все эти чистильщики и оптимизаторы проходят по той же статье, что и «удвоители объёма ОЗУ», если кто-то помнит такие программы из девяностых.
        image

        Ну и прочие «чистильщики реестра».

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

        PS. Кстати, дальше можно написать программу, которая будет в /etc лишние строчки из конфигов вычищать (пустые и комментарии) для экономии места на диске. ;)


  1. DownFvll
    20.01.2023 01:57

    А теперь чутка документации на drop_caches (её иногда полезно читать):

    Use of this file can cause performance problems. Since it discards cached objects, it may cost a significant amount of I/O and CPU to recreate the dropped objects, especially if they were under heavy use. Because of this, use outside of a testing or debugging environment is not recommended.

    А также по поводу sync перед дропом кэшей:

    This is a non-destructive operation and will not free any dirty objects. To increase the number of objects freed by this operation, the user may run `sync' prior to writing to /proc/sys/vm/drop_caches. This will minimize the number of dirty objects on the system and create more candidates to be dropped.

    И что если в свопе больше чем RAM может вместить, а система пытается дропнуть весь своп обратно в память?