Recientemente en GUTL hemos estado comentando algunos de los problemas relativos a la gestión de la memoria cache en Linux, particularmente en Debian. En algunas ocasiones mi portátil llegaba al punto del colapso, no tenía más remedio que liberar la memoria cache manualmente, y en casos extremos: reiniciaba el sistema. Esto es debido a que cuando tenemos muchas aplicaciones abiertas, aunque cerremos una buena parte de ellas, estas quedan en la memoria ram (cache). La próxima vez que las abramos tardarán mucho menos en ejecutarse.
Memoria caché:
Área de almacenamiento dedicada a los datos usados o solicitados con más frecuencia para su recuperación a gran velocidad.
Sin embargo, lo que debería ser una ventaja, en ocasiones supone un problema. En máquinas de bajos recursos cuando necesitamos iniciar otras aplicaciones, es probable que no dispongan de la suficiente memoria ram para ejecutarse de manera fluida. Para ello es necesario liberar la memoria cache ejecutando el siguiente comando: sync; echo 3 > /proc/sys/vm/drop_caches
.
Hay varias formas de gestionar esta tarea mediante la creación de scripts. Aquí en el portal GUTL hay buena información al respecto: liberando memoria ram desde la terminal o consola y como limpiar los caches de memoria en gnulinux.
Personalmente suelo utilizar un script muy pequeño para facilitar esta tarea. En resumidas cuentas:
Contenido del archivo: limpiar-cache.sh
#!/bin/sh sync && echo 3 > /proc/sys/vm/drop_caches
permisos de ejecución y carpeta destino:
sudo chmod +x limpiar-cache.sh sudo cp limpiar-cache.sh /usr/local/bin
Invocando: limpiar-cache.sh desde la consola mitigaba el problema. También supe hacer uso del comando crontab para prescindir de la terminal, y que el script se ejecutara cada cierto tiempo. El problema es que en muchos casos limpiaba la cache cuando no lo necesitaba, y en otras ocasiones, estaba expectante a que crontab hiciera su trabajo. Esta idea no me daba el resultado que yo deseaba, volví al método manual. Cabe aclarar que ahora sería factible su uso.
Finalmente —a raíz de un comentario de Pablo (@elMor3no)— me decidí a crear un script automatizado muy sencillo, que tenga parámetros preestablecidos, y en función de estos, realice la tarea sin mi intervención. Se trata de un bucle infinito, pero no hay de que preocuparse, no consume nada. Básicamente el script sera gestionado por systemd. Aunque no soy un gran admirador de este, admito que tiene sus cosas buenas: como lo práctico.
El script
El script con permisos de ejecución está alojado en la ruta /root/scripts/, no obstante, podría estar alojado en otra ruta, como: /usr/local/bin.
sudo chmod +x control-cache.sh sudo mkdir /root/scripts sudo cp control-cache.sh /root/scripts
Archivo: /root/scripts/control-cache.sh
#!/bin/sh # Control de la Memoria Cache memoria_minima=300 tiempo_espera=15 while true; do free_memory=`free -m | grep Mem | awk '{print $4}'` if [ $free_memory -le $memoria_minima ]; then sync; echo 3 > /proc/sys/vm/drop_caches fi sleep $tiempo_espera done
Una breve descripción de su función
memoria_minima: Aquí se define el piso mínimo (umbral) en donde queremos que comience a liberase memoria cache. En este caso está fijado en 300MB de memoria ram disponible.
tiempo_espera: Este valor es importante, y establece el tiempo que tardará en volver a ejecutarse el bucle (while) finalizada la última sentencia. Es tarea del usuario establecer un valor razonable.
free_memory: Esta variable guarda el estado actual de la memoria ram disponible, dicho valor será comparado con la memoria mínima asignada por el usuario (umbral). El tiempo entre cada comparación está determinado por la sentencia: sleep $tiempo_espera
Obtención del valor free_memory utilizando grep y awk para filtrar:
En la próxima linea empleo una condicional (if): «Si la memoria (free) disponible es menor o igual que el valor mínimo asignado por el usuario» ejecutar la próxima sentencia: sync; echo 3 > /proc/sys/vm/drop_caches
. Seguidamente, se haya cumplido o no la condición, espera el tiempo establecido por el usuario, y vuelve a ejecutarse el ciclo. De acuerdo con estos valores, cuando la memoria ram disponible toque el piso de los 300MB: libera la cache, espera 15 segundos, y vuelve a iniciar el ciclo de comprobación.
El tiempo de espera (sleep) es particularmente importante porque de otra forma aumentaría los ciclos de la cpu. Además, cuando perfore el piso mínimo —300MB en este caso—, de mantenerse por un tiempo, por ej.: en 285MB – 290MB, se estará ejecutando: sync; echo 3 > /proc/sys/vm/drop_caches
hasta leer un valor superior a 300MB, en el cual se detendrá. En este hipotético caso se estaría liberando memoria cada 15 segundos, por lo tanto, un tiempo razonable sería de 30 a 60 segundos, aunque con 15 seg. se desempeñó bastante bien. Depende de cada uno establecer ese valor, al igual que el piso mínimo de la memoria ram.
Archivo de unidad (systemd)
Llegó el momento de gestionar el script control-cache.sh como un servicio. Con privilegios root edité el archivo de unidad control-cache.service en el directorio /etc/systemd/system/. A este archivo no hay que asignarle permisos de ejecución.
Contenido del archivo: /etc/systemd/system/control-cache.service
[Unit] Description=Control de la Memoria Cache [Service] Type=simple ExecStart=/root/scripts/control-cache.sh WorkingDirectory=/root/scripts Restart=on-failure StandardOutput=syslog StandardError=syslog [Install] WantedBy=multi-user.target
Descargar control-cache.service
No hay mucho que decir, es un archivo de unidad bastante simple de entender:
Type=simple: es el servicio por defecto, debe iniciarse inmediatamente, además el proceso no debe romperse. No utilizar este tipo si otros servicios tienen que ser llamados por ese servicio, a menos que no sea activado por el socket.
ExecStart=: como su nombre lo indica, es el encargado de ejecutar el script en la ruta establecida.
WorkingDirectory=: directorio de trabajo, generalmente el mismo donde se aloja la aplicación (script).
Restart=on-failure=: reinicia el servicio en caso de fallar.
StandardOutput=: salida estándar de los registros (log), si no se especifica nada, por defecto escribirá en el archivo /var/log/syslog. En caso de especificarse null, redirige los registros a /dev/null.
StandardError=: ídem al anterior para casos de error.
WantedBy=multi-user.target=: es el análogo al nivel 3 en SystemV, y permite habilitar el script para que se inicie en el arranque del sistema.
sudo systemctl daemon-reload
para que se apliquen los cambios.Habilitar el archivo de servicio
Una vez que tengamos ambos archivos en sus respectivas rutas: /root/scripts/control-cache.sh y /etc/systemd/system/control-cache.service, es momento de manipular el servicio mediante los siguientes comandos:
Arranque, parada y reinicio:
sudo systemctl start control-cache.service sudo systemctl stop control-cache.service sudo systemctl restart control-cache.service
verificar que haya iniciado correctamente:
sudo systemctl status control-cache.service
Si todo ha ido bien, podemos habilitarlo en el arranque:
sudo systemctl enable control-cache.service
La siguiente imagen muestra el servicio en estado habilitado en el inicio del sistema y activo:
También es posible controlarlo con los siguientes comandos:
sudo service control-cache start | stop | status
Testear el script
Para asegurarte de que el script se adapta a tus exigencias, o simplemente quieres saber como se comporta, puedes realizar algunas pruebas de estrés de la siguiente forma: en 3 terminales, o una sola terminal dividida en 3 ventanas (tmux, terminator), en lo posible elige la opción «Siempre encima» para que no pierdan el foco. En cada una escribir el siguiente comando:
- Terminal 1:
watch free -m
- Terminal 2:
tail -f /var/log/syslog
- Terminal 3:
htop
Antes de abrir aplicaciones, chequear en htop (terminal 3) que los ciclos de cpu están bien. A continuación observando la memoria libre disponible (terminal 1), comienza a abrir aplicaciones hasta aproximarse al umbral que escogiste, supongamos: 300MB, e intenta perforar ese piso por unos pocos megas —digamos 280, 295—. El tiempo de respuesta estará dado entre: 1 seg. y el tiempo de espera que seleccionaste (ej.: 15 seg.). Observa el registro de syslog (terminal 2) y comprueba que el script está respondiendo.
Luego prueba mantener aplicaciones abiertas, a tal punto, que no pueda superar el techo de los 300MB. Observa el registro syslog y verifica que el tiempo de espera para limpiar la memoria cache, en repeticiones consecutivas, es el que se ajusta a tus necesidades. No descuidar Htop.
Consideraciones finales
También es posible automatizar esta tarea mediante crontab —aunque personalmente, a modo de gestionar el script, prefiero systemd—. Por ejemplo, realizar una tarea cada 30 segundos todos los días: 30 * * * * /root/scripts/control-cache.sh
. En este caso el script solo debe contar con la linea de comprobación, el ciclo lo realiza crontab:
#!/bin/sh # Control de la Memoria Cache memoria_minima=300 free_memory=`free -m | grep Mem | awk '{print $4}'` if [ $free_memory -le $memoria_minima ]; then sync; echo 3 > /proc/sys/vm/drop_caches fi
El script no hace magia, y lamentablemente tampoco gestiona la ram, eso es tarea del sistema. control-cache.sh simplemente intenta otorgarle independencia al usuario, para que no tenga que estar todo el tiempo expectante. Espero que a alguien le sea utilidad.
Fuente:
https://wiki.archlinux.org/index.php/Systemd_(Español)#Tipos_de_servicios
Magistral clase de dominio de nuestro sistema. Te aseguro que la «Trilobite» (mi laptop personal) te lo va a agradecer (aunque lo que tenga sea Lubuntu con LXQt y no el Debian que mencionas como ejemplo).
Ojala podamos retomar este tipo de publicaciones mas seguidamente en nuestro portal. Mil gracias por el aporte… voy a probarlo y te digo
Gracias @Neji
A mi personalmente me da error a la hora de activarlo como servicio:
neji@neji-laptop:~$ sudo systemctl status control-cache.service
● control-cache.service
Loaded: loaded (/etc/systemd/system/control-cache.service; enabled; vend
Active: failed (Result: exit-code) since Tue 2019-12-17 20:53:44 CST; 14
Process: 2644 ExecStart=/usr/local/bin/limpiar-cache.sh (code=exited, sta
Main PID: 2644 (code=exited, status=203/EXEC)
dic 17 20:53:44 neji-laptop systemd[1]: control-cache.service: Service Rest
dic 17 20:53:44 neji-laptop systemd[1]: control-cache.service: Scheduled re
dic 17 20:53:44 neji-laptop systemd[1]: Stopped control-cache.service.
dic 17 20:53:44 neji-laptop systemd[1]: control-cache.service: Start reques
dic 17 20:53:44 neji-laptop systemd[1]: control-cache.service: Failed with
dic 17 20:53:44 neji-laptop systemd[1]: Failed to start control-cache.serv
A lo mejor es porque lo puse en /usr/local/bin y no en /root/scripts como tu dices??
Hola @Neji:
En el archivo de systemd estás usando ExecStart=/usr/local/bin/limpiar-cache.sh. Corrobora que en /usr/local/bin se llame limpiar-cache.sh y que tenga permisos de ejecución. Ese error generalmente se debe a que no concuerdan los nombres.
En caso de que figure /usr/local/bin/control-cache.sh, edita a: ExecStart=/usr/local/bin/contol-cache.sh. Luego un
sudo systemctl daemon-reload
.El script que automatiza la tarea es control-cache.sh. No se si le cambiaste el nombre en ‘/usr/local/bin’ o utilizaste el ejemplo: limpiar-cache.sh, el cuál describí más arriba y no es el que controla la memoria.
Saludos.
Llamé limpiar-cache.sh al archivo que realiza la tarea y control-cache.service al servicio.
limpiar-cache.sh tiene los permisos de ejecución dados, systemd me lo da como disponible pero no lo activa.
Descargué ambos archivos de aquí (GUTL), renombré y le di permisos a limpiar-cache.sh, lo copié en /usr/local/bin/ y funciona.
● control-cache.service - Control de la Memoria Cache
Loaded: loaded (/etc/systemd/system/control-cache.service; disabled; vendor preset: enabled)
Active: active (running) since Thu 2019-12-19 12:17:36 -03; 4s ago
Main PID: 4023 (limpiar-cache.s)
Tasks: 2 (limit: 2255)
Memory: 1000.0K
CGroup: /system.slice/control-cache.service
├─4023 /bin/sh /usr/local/bin/limpiar-cache.sh
└─4033 sleep 15
dic 19 12:17:36 debian systemd[1]: Started Control de la Memoria Cache.
Lo que debe estar sucediendo es que no editaste la ruta WorkingDirectory a /usr/local/bin en control-cache.service
[Service]
Type=simple
ExecStart=/usr/local/bin/limpiar-cache.sh
WorkingDirectory=/usr/local/bin
Restart=on-failure
StandardOutput=syslog
StandardError=syslog
Yo cree el script mio a partir del tuyo….
#!bin/sh
# Controlar la Cache de forma Automatica
# Script basado en el original de Percaff_TI99 (GUTL)
minimo=143
espera=15
while true; do
#Analizando cuanta memoria libre queda
memoria_libre=`free -m | grep Mem | awk '{print $4}'`
#Si la memoria libre es menor o igual que el minimo limpio cache
if [ $memoria_libre -le $minimo ]; then
sync; echo 3 > /proc/sys/vm/drop_caches
fi
sleep $espera
done
Edite el servicio como mismo tu dices
[unit]
Description=Controla la Memoria Cache de Linux
[Service]
Type=simple
ExecStart=/usr/local/bin/limpiar-cache.sh
WorkingDirectory=/usr/local/bin
Restart=on-failure
StandardOutput=syslog
StandardError=syslog
[Install]
WantedBy=multi-user.target
Luego puse disponible el servicio pero da problemas a la hora de activarlo…. he hecho como 15 veces lo de systemctl daemon-reload pero sigue sin activarse el script.
El script que hiciste funciona, el problema está en la primera linea:
#!bin/sh
por#!/bin/sh
.Además en el archivo de servicio
[unit]
por[Unit]
. Sino te va a salir el error /etc/systemd/system/control-cache.service:1: Unknown section ‘unit’. Aunque igual funciona.Cuando hagas los cambios en ambos archivos, dale a:
sudo systemctl daemon-reload
,sudo systemctl start control-cache.service
.Si estaba activo:
sudo systemctl restart control-cache.service
No deberías tener problemas, más que nada, era ese pequeño detalle en el script.
Mil gracias… he corregido el script y el servicio y afortunadamente ya puedo ver en mi consola algo como esto:
neji@neji-laptop:~$ sudo systemctl status control-cache.service
[sudo] password for neji:
● control-cache.service - Controla la Memoria Cache de Linux
Loaded: loaded (/etc/systemd/system/control-cache.service; enabled;
Active: active (running) since Fri 2019-12-20 20:37:11 CST; 7min ag
Main PID: 14909 (limpiar-cache.s)
CGroup: /system.slice/control-cache.service
├─14909 /bin/sh /usr/local/bin/limpiar-cache.sh
└─15680 sleep 15
dic 20 20:37:11 neji-laptop systemd[1]: Started Controla la Memoria Ca
dic 20 20:37:11 neji-laptop systemd[14909]: Failed to attach 14909 to
Me alegro @Neji. Veo que figura un error: «Failed to attach 14909», pero seguramente cuando reinicie la portátil no debería estar. Yo lo probé copiando/pegando tu script (con los cambios mencionados) y funciona correctamente, sin ningún tipo de advertencia.
Saludos.
Magnífico
Gracias @MrAtom
Hahhha yo pense que era el unico loco que tenia su propio script :V hahaha, solo que el mio se meten rm en los /var/log , /tmp …
En este script se pueden evitar mandándolos al /dev/null, aunque creo que probé y seguían apareciendo en syslog. Desde una versión en adelante de systemd funciona.
Borrar todos los /var/logs es como que te deja en ascuas si tienes algún problema con el sistema.
Saludos.