Inicias sesión, ejecutas free y se te encoge el estómago: la memoria aparece “usada” como si no hubiera mañana. No hay nada ardiendo a la vista. La latencia parece correcta. La CPU está aburrida. Aun así, el panel grita: RAM 92%. Alguien pregunta: “¿Fuga de memoria?”
A veces eso es un incidente real. Otras veces es solo Linux haciendo su trabajo, usando RAM libre como caché porque la memoria sin usar es una oportunidad desperdiciada. El truco es saber cuál es cuál—rápido—sin sacrificios rituales a los dioses del kernel.
El modelo mental: la RAM no es un cubo, es un mercado
Si te llevas una idea de este artículo, que sea esta: “uso elevado de RAM” no es un diagnóstico. Es una observación, y con frecuencia una saludable.
Tres tipos de memoria que se confunden en las alertas
- Memoria anónima: heap de procesos, pilas, arenas de malloc, heap de Java, heap de Node/V8, etc. Si esto crece sin control, podrías tener una fuga o una carga sin límites.
- Memoria respaldada por archivo: archivos mapeados, bibliotecas compartidas, bases de datos mapeadas en memoria, y especialmente la page cache. Aquí es donde Linux mantiene datos de archivos porque leer desde RAM es más rápido que desde disco.
- Memoria del kernel: caches slab, buffers de red, dentries/inodes y otras estructuras del kernel. Esto puede crecer por razones buenas (tráfico) o malas (bugs, mala configuración).
Por qué “memoria libre” es una métrica engañosa
Linux quiere que la memoria libre esté cerca de cero. No porque sea descuidado, sino porque la memoria inactiva no hace nada. El kernel usa RAM oportunísticamente para caché y la recupera cuando las aplicaciones la necesitan.
Así que cuando alguien dice “la RAM está llena”, la siguiente pregunta es: ¿llena de qué? La caché es reclamable. El heap filtrado no lo es (hasta que el proceso muere).
Dos reglas que te mantienen fuera de problemas
- Si la latencia es estable y no hay thrash de reclaim, deja de entrar en pánico. Un sistema con mucha caché puede verse “lleno” y estar perfectamente sano.
- Si el swap crece y los fallos mayores se disparan, estás pagando intereses sobre deuda de memoria. Ahí es donde nacen los incidentes de producción.
Una verdad fría: el “% de RAM” del panel suele ser una mala abstracción. Necesitas señales de presión, no solo ocupación.
Hechos e historia interesantes (breve, concreto y útil)
- El comportamiento “buff/cache” de Linux ha confundido a administradores durante décadas; la salida moderna de
freeañadióavailablepara reducir falsas alarmas. - Windows popularizó el término “standby memory” para caché reclamable; Linux hace lo mismo, solo con etiquetas y herramientas distintas.
- El OOM killer existe porque el overcommit perfecto de memoria es imposible: cuando el kernel no puede satisfacer asignaciones, elige un proceso para matar antes que dejar el sistema en deadlock.
- Los contenedores no inventaron los límites de memoria; los cgroups lo hicieron. Los contenedores solo hicieron más fácil aplicar cgroups a todo (incluida tu base de datos, que entonces se queja fuerte).
- Los sistemas Unix tempranos eran parcos con la page cache porque la RAM era cara; los kernels modernos son agresivos porque los ciclos de CPU y la espera de I/O cuestan más que la RAM.
- El ARC de ZFS es básicamente “page cache, pero para ZFS” y puede dominar la RAM si se lo permites; no es una fuga, es una estrategia.
- Transparent Huge Pages (THP) pueden mejorar rendimiento—o generar picos de latencia y bloat de memoria, dependiendo de la carga y la fragmentación.
- Los reportes de memoria de Java son notoriamente confusos: el heap es solo parte; el RSS incluye asignaciones nativas, JIT, pilas de threads y mapeos de archivos.
- Linux puede reclamar page cache limpia rápidamente pero las páginas sucias requieren writeback; si el writeback es lento, “reclaimable” se convierte en “no ahora mismo”.
Cómo se ve la RAM alta “normal” vs la RAM alta “rota”
Normal: RAM usada como caché (rápido, silencioso y reversible)
Lo normal se ve así:
freemuestra “used” alto pero tambiénavailablealto.- Bajo uso de swap (o swap estable que no sube).
vmstatmuestrasi/sobajos (swap-in/out) ywabajo (espera de I/O).- La latencia de disco es baja porque los aciertos de caché son altos.
- El RSS de los procesos es estable; nada se está inflando.
Esto es el kernel siendo útil. Por lo general puedes dejarlo en paz. Si “lo arreglas” limpiando caché en un cron, no estás optimizando; te estás saboteando.
Roto: presión de memoria y thrash de reclaim
Lo roto se ve así:
availablees bajo y está cayendo.- La actividad de swap aumenta (
si/sono nulo durante periodos sostenidos). - Los fallos de página mayores se disparan; la latencia se vuelve extraña.
- Aparecen mensajes del OOM killer en los registros.
kswapddel kernel aparece en perfiles de CPU, porque la máquina está ocupada intentando encontrar memoria para respirar.
En ese punto la pregunta cambia de “¿por qué la RAM está alta?” a “¿qué la está consumiendo y podemos recuperarla de forma segura?”
Las tres causas más comunes de “está roto”
- Fuga real de la aplicación o crecimiento de memoria sin límite: encolar datos en RAM, cachés sin eviction, crecimiento en buffers por conexión, etc.
- Caches mal dimensionados: buffers de base de datos, heap de JVM, maxmemory de Redis, ARC de ZFS, caché de CDN, LRU a nivel de aplicación que no es realmente LRU.
- Crecimiento de memoria del kernel: caches slab, buffers de red, tablas conntrack, cachés de metadatos de sistemas de archivos bajo churn.
Broma #1: Las fugas de memoria son como la purpurina: no la ves al principio, luego de repente está en cada rincón de tu vida.
Plan rápido de diagnóstico (primero/segundo/tercero)
Primero: Determina si esto es presión o solo ocupación
- Revisa
freebuscandoavailable. - Revisa la tendencia de swap y
vmstatpor actividad sostenida de swap. - Busca eventos OOM en los registros.
Decisión: Si available está sano y el swap no sube, considéralo caché normal a menos que haya síntomas visibles para usuarios.
Segundo: Identifica la clase de memoria
- ¿Es RSS de procesos (unos pocos PIDs creciendo)?
- ¿Es page cache (caché alto, anon estable)?
- ¿Es slab del kernel (slab alto, objetos creciendo)?
- En contenedores: ¿es tema de límite de cgroup (RSS bien, pero cgroup reporta cerca del límite)?
Decisión: Elige la herramienta adecuada: inspección por proceso, estadísticas de cgroup, o desglose de slab—no “reiniciar todo” como método diagnóstico.
Tercero: Prueba el mayor consumidor y elige la mitigación menos riesgosa
- Obtén los principales consumidores de memoria y confirma crecimiento a lo largo del tiempo (no solo una instantánea).
- Verifica si el consumidor es configurable (límite de caché) o con bug (fuga).
- Mitiga: limitar caché, arreglar consulta/carga, añadir memoria, o reiniciar como parche controlado con acciones de seguimiento.
Decisión: Si el sistema está bajo presión activa, prioriza estabilidad: evita OOM, detén el thrash, luego haz la causa raíz con calma.
Tareas prácticas: comandos, salidas y decisiones
Estas son tareas reales que puedes ejecutar en hosts Linux de producción. Cada una incluye lo que la salida significa y la decisión que impulsa. Úsalas en orden, no al azar.
Tarea 1: Lee la memoria como un adulto (free -h)
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 31Gi 26Gi 600Mi 1.2Gi 4.5Gi 3.8Gi
Swap: 4.0Gi 512Mi 3.5Gi
Qué significa: “used” incluye caché y otros reclamables. El número que te importa primero es available (aprox.: cuánto se puede asignar sin swapear).
Decisión: Si available son varios GiB y está estable, probablemente sea caché normal. Si es bajo (<5–10% del total) y sigue cayendo, pasa a comprobaciones de presión.
Tarea 2: Confirma presión y churn de swap (vmstat 1)
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 524288 612000 82000 3920000 0 0 5 22 430 900 12 4 83 1 0
1 0 524288 598000 82000 3950000 0 0 1 10 420 880 11 4 84 1 0
3 1 525312 120000 81000 2800000 150 320 800 900 1200 2500 25 12 35 28 0
2 1 540000 90000 80000 2700000 220 400 1100 1400 1500 3000 22 15 30 33 0
2 1 560000 70000 79000 2600000 180 380 900 1200 1400 2900 20 14 32 34 0
Qué significa: si/so sostenidos no cero indican swap. wa creciente sugiere que la máquina espera I/O, muchas veces agravado por swap o writeback.
Decisión: Si el churn de swap es sostenido, trátalo como un incidente: reduce uso de memoria o aumenta memoria/límites antes de que la latencia colapse o aparezca un OOM.
Tarea 3: Busca evidencia del OOM killer (journalctl)
cr0x@server:~$ journalctl -k -S -2h | egrep -i 'oom|out of memory|killed process' | tail -n 20
Feb 05 09:41:12 server kernel: Out of memory: Killed process 21784 (java) total-vm:9876544kB, anon-rss:2456789kB, file-rss:12345kB, shmem-rss:0kB
Qué significa: El kernel se quedó sin memoria asignable bajo sus restricciones y mató algo. Ese “algo” a menudo no es la causa raíz—solo la víctima desafortunada con la puntuación equivocada.
Decisión: Si ves kills por OOM, deja de debatir definiciones y comienza a reducir la presión de memoria inmediatamente. Luego haz la investigación de la causa raíz.
Tarea 4: Ver el desglose de memoria a nivel sistema (cat /proc/meminfo)
cr0x@server:~$ egrep 'MemTotal|MemAvailable|Buffers|Cached|SwapTotal|SwapFree|Active|Inactive|AnonPages|Slab|SReclaimable|Dirty|Writeback' /proc/meminfo
MemTotal: 32803520 kB
MemAvailable: 4012340 kB
Buffers: 112340 kB
Cached: 3890120 kB
SwapTotal: 4194300 kB
SwapFree: 3670016 kB
Active: 20123456 kB
Inactive: 8765432 kB
AnonPages: 22123456 kB
Slab: 1456780 kB
SReclaimable: 612340 kB
Dirty: 245600 kB
Writeback: 4200 kB
Qué significa: AnonPages es un proxy aproximado de la memoria privada de procesos. Cached es page cache. Slab/SReclaimable te habla de caches del kernel. Dirty/Writeback indica si el reclaim está bloqueado por flushing.
Decisión: AnonPages alto te apunta a procesos/cgroups. Slab alto te apunta a crecimiento de objetos del kernel. Dirty alto sugiere problemas de writeback y cuellos de botella en I/O.
Tarea 5: Identificar procesos top por RSS (ps)
cr0x@server:~$ ps -eo pid,user,comm,rss,vsz --sort=-rss | head -n 15
PID USER COMMAND RSS VSZ
21784 app java 3854120 9876544
10422 app node 1123400 2456780
2314 postgres postgres 823000 1024000
1981 root dockerd 412000 1650000
1450 root systemd-journ 180000 450000
Qué significa: RSS es resident set size: memoria realmente en RAM (incluyendo algunos mapeos respaldados por archivos). VSZ es virtual, a menudo enorme y muchas veces irrelevante.
Decisión: Si un proceso domina y crece con el tiempo, sospecha fuga o caché mal dimensionada. Si el RSS está repartido entre muchos procesos, sospecha expansión de carga o densidad de contenedores.
Tarea 6: Inspeccionar mappings de un proceso sospechoso (pmap -x)
cr0x@server:~$ sudo pmap -x 21784 | tail -n 5
00007f2c78000000 262144 260000 260000 rw--- [ anon ]
00007f2c88000000 262144 262144 262144 rw--- [ anon ]
00007f2c98000000 262144 262144 262144 rw--- [ anon ]
00007ffd2c1b1000 132 44 44 rw--- [ stack ]
total kB 9876544 3854120 3720000
Qué significa: Regiones anónimas grandes apuntan a heap/asignaciones nativas. Mapeos respaldados por archivo grandes pueden ser archivos mmap’d o libs compartidas.
Decisión: Si el RSS anónimo está inflándose, necesitas investigación a nivel aplicación (heap dump, profiling, eviction de caché). Si es respaldado por archivo, considera el comportamiento de page cache/mmap y el patrón de I/O.
Tarea 7: Detectar si el kernel pasa tiempo reclamando (sar -B)
cr0x@server:~$ sar -B 1 3
Linux 6.5.0 (server) 02/05/2026 _x86_64_ (16 CPU)
12:01:01 AM pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff
12:01:02 AM 5.00 22.00 1200.00 0.00 8000.00 0.00 0.00 0.00 0.00
12:01:03 AM 900.00 1400.00 9000.00 85.00 12000.00 4500.00 0.00 3200.00 71.11
12:01:04 AM 850.00 1350.00 8700.00 90.00 11800.00 4700.00 0.00 3100.00 65.96
Qué significa: Fallos mayores (majflt/s) y scanning/stealing indican actividad de reclaim. %vmeff da una idea de la eficiencia del reclaim; baja eficiencia suele correlacionar con thrash.
Decisión: Fallos mayores altos + escaneo intenso = estás en presión. Arregla uso de memoria o límites; no te limites a “añadir swap y esperar”.
Tarea 8: Examinar consumidores de slab del kernel (slabtop)
cr0x@server:~$ sudo slabtop -o -s c | head -n 15
Active / Total Objects (% used) : 812345 / 845000 (96.1%)
Active / Total Slabs (% used) : 22000 / 22000 (100.0%)
Active / Total Caches (% used) : 95 / 120 (79.2%)
Active / Total Size (% used) : 1456780.00K / 1520000.00K (95.8%)
Minimum / Average / Maximum Object : 0.01K / 0.18K / 8.00K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
220000 219500 99% 0.19K 11000 20 440000K dentry
180000 179000 99% 0.94K 9000 20 360000K inode_cache
95000 94900 99% 0.05K 1250 76 47500K kmalloc-64
Qué significa: Grandes dentry/inode_cache suelen indicar churn de metadatos de sistema de archivos (muchos archivos). Esto puede ser normal en servidores de builds, log shippers o sistemas que escanean directorios.
Decisión: Si slab es enorme y crece, investiga la carga (file storms), bugs del kernel o parámetros como vm.vfs_cache_pressure (con precaución). No uses “drop caches” en producción como práctica habitual.
Tarea 9: Comprobar límites de memoria de cgroup (contenedores/systemd)
cr0x@server:~$ cat /sys/fs/cgroup/memory.max
8589934592
cr0x@server:~$ cat /sys/fs/cgroup/memory.current
8422686720
Qué significa: Puedes tener mucha RAM en el host pero aun así OOM dentro de un cgroup porque el límite es estricto. memory.current cerca de memory.max es presión independientemente de la memoria libre del host.
Decisión: Si el cgroup está cerca del límite, sube el límite o reduce la carga/caches dentro del contenedor. La “memoria libre” del host no te salvará.
Tarea 10: Identificar eventos OOM de cgroup (dmesg / log del kernel)
cr0x@server:~$ dmesg | egrep -i 'memory cgroup out of memory|oom-kill|Killed process' | tail -n 10
[123456.789012] Memory cgroup out of memory: Killed process 10422 (node) total-vm:2456780kB, anon-rss:980000kB, file-rss:12000kB, shmem-rss:0kB
Qué significa: Eso es un OOM de contenedor/cgroup, no necesariamente un OOM del host. La remediación son límites, no “limpiar caché”.
Decisión: Ajusta límites de cgroup y establece requests/limits realistas. Si no lo haces, estás jugando a la lotería donde el premio es downtime.
Tarea 11: Entender “memoria faltante” vía smaps rollup
cr0x@server:~$ sudo cat /proc/21784/smaps_rollup | egrep 'Rss|Pss|Private|Shared|Swap'
Rss: 3854120 kB
Pss: 3801200 kB
Shared_Clean: 12000 kB
Shared_Dirty: 4000 kB
Private_Clean: 35000 kB
Private_Dirty: 3803120 kB
Swap: 120000 kB
Qué significa: Private_Dirty es una señal fuerte de memoria anónima privada—a menudo heap. Swap aquí significa que el proceso está pagando la tasa del swap.
Decisión: Si private dirty crece con la carga y no baja, planifica una corrección en la aplicación. Si el swap crece, considera ajustar límites de memoria e investiga hotspots.
Tarea 12: Revisar descriptores abiertos y presión de mmap (lsof)
cr0x@server:~$ sudo lsof -p 21784 | wc -l
18234
Qué significa: Muchos FDs pueden correlacionarse con buffers por conexión, grandes sets de mmap y, a veces, fugas (fuga de FDs no es fuga de RAM, pero suele viajar con una).
Decisión: Si el conteo de FDs sube sin límite, trátalo como clase de fuga. Corrige la app; aumenta ulimits solo como parche temporal.
Tarea 13: Rastrear tendencia de memoria en el tiempo (ps loop)
cr0x@server:~$ for i in {1..5}; do date; ps -p 21784 -o pid,rss,etime,cmd; sleep 60; done
Mon Feb 5 10:00:00 UTC 2026
PID RSS ELAPSED CMD
21784 3720000 01:22:10 java -jar service.jar
Mon Feb 5 10:01:00 UTC 2026
PID RSS ELAPSED CMD
21784 3755000 01:23:10 java -jar service.jar
Mon Feb 5 10:02:00 UTC 2026
PID RSS ELAPSED CMD
21784 3812000 01:24:10 java -jar service.jar
Mon Feb 5 10:03:00 UTC 2026
PID RSS ELAPSED CMD
21784 3899000 01:25:10 java -jar service.jar
Mon Feb 5 10:04:00 UTC 2026
PID RSS ELAPSED CMD
21784 3980000 01:26:10 java -jar service.jar
Qué significa: La tendencia de crecimiento vence a una sola instantánea. Si el RSS sube de forma sostenida, no estás viendo “caché”; estás viendo acumulación.
Decisión: Escala a profiling y mitigación a nivel de código; implementa guardarraíles (límites, backpressure) mientras lo arreglas.
Tarea 14: Comprobar congestión de writeback (grep contadores vmstat)
cr0x@server:~$ egrep 'nr_dirty|nr_writeback|pgscan|pgsteal|oom_kill' /proc/vmstat | head
nr_dirty 61234
nr_writeback 2100
pgscan_kswapd 987654
pgsteal_kswapd 765432
oom_kill 3
Qué significa: Escaneos/steal altos indican trabajo de reclaim. Los niveles dirty/writeback dan pistas sobre si el reclaim está bloqueado por flushes lentos.
Decisión: Si el writeback está elevado y el I/O es lento, arregla rendimiento de almacenamiento o límites de dirty; de lo contrario la presión de memoria se sentirá peor de lo “que debería”.
Tres microhistorias corporativas desde las trincheras de la memoria
Microhistoria 1: El incidente causado por una suposición equivocada
Una empresa mediana operaba una flota de VMs Linux detrás de un balanceador. Su herramienta de monitorización tenía un único métrico principal: “RAM usada %.” Avisaba al 85%. Avisaba con frecuencia. La gente aprendió a ignorarlo, que es un truco fino hasta que deja de serlo.
Una tarde la alerta de RAM saltó en un nodo crítico de API. El on-call miró por encima: usado 90%, CPU bien. Encogió de hombros—“es solo caché”—y volvió a lo que sea que haga la gente cuando no la llaman.
Treinta minutos después la latencia subió y luego cayó en picado. El nodo empezó a fallar en los checks de salud y fue sacado del balanceador. Un segundo nodo siguió. Luego un tercero. Ahora era un outage.
La causa raíz no fue la page cache. Un despliegue nuevo introdujo una cola en memoria sin límite cuando una dependencia aguas abajo se ralentizó. El gráfico de “used %” parecía como siempre, pero MemAvailable se estaba colapsando y el churn de swap subía. Tenían un problema de presión y lo trataron como un problema cosmético.
La solución fue doble: implementar backpressure y meter MemAvailable, actividad de swap y eventos OOM en las alertas primarias. La suposición equivocada no fue “Linux usa caché.” La suposición equivocada fue “alto used significa lo mismo siempre.”
Microhistoria 2: La optimización que salió mal
Un equipo de ingeniería quiso reducir I/O de disco en un servicio de procesamiento de logs. Aumentaron considerablemente un caché interno. Funcionó en staging y las gráficas quedaron geniales: menos lecturas, throughput más suave.
En producción, el mismo cambio provocó una falla en cámara lenta. El tráfico pico calentó rápido el caché, lo que aumentó el RSS. Eso por sí solo habría estado bien—las máquinas tenían RAM suficiente. Pero el servicio corría en contenedores con límites de memoria conservadores establecidos meses antes cuando el tráfico era menor y la “eficiencia” era un KPI.
El cgroup empezó a reclamar agresivamente. La latencia aumentó. El servicio reintentó más, lo que aumentó memoria, lo que aumentó reclaim. Entonces el OOM killer de cgroup comenzó a terminar contenedores. El reinicio automático empeoró las cosas porque creó manadas de calentamiento del caché.
La lección post-mortem no fue “los cachés son malos.” Fue “los cachés son cargas.” Si cambias el perfil de memoria, debes cambiar límites y alarmas. Si no, acabas trasladando el cuello de botella a una caja más pequeña y te sorprendes cuando duele.
Microhistoria 3: La práctica aburrida pero correcta que salvó el día
Una compañía del sector financiero corría un clúster de bases de datos y varios servicios en los mismos hosts. No es lo ideal, pero los presupuestos son una ley física real. Un SRE insistió en un simulacro semanal: registrar desgloses base de memoria y mantener un runbook con los rangos “normales conocidos”: page cache, slab, buffers de BD y RSS típico de cada servicio.
Era tedioso. No producía dopamina. También significó que cuando la memoria empezó a subir en un conjunto de nodos, no discutieron si era normal—lo compararon con la línea base.
Los slab estaban dentro del rango normal, la page cache era típica, pero AnonPages estaba más alta que la línea base por unos cuantos GiB y subiendo. El top RSS apuntó a un sidecar que “no debería hacer mucho.” Esa frase es un buen predictor de trabajo futuro.
Revirtieron el cambio del sidecar antes de cualquier OOM. El análisis posterior mostró una actualización de librería que cambió el comportamiento de buffering en ciertos patrones de respuesta. La salvación no fue heroica. Fue tener una línea base y confiar en ella.
Errores comunes: síntoma → causa raíz → solución
1) Síntoma: “La RAM está 95% usada, debe ser una fuga”
Causa raíz: Interpretar “used” como “no disponible.” La page cache infla “used” y es reclamable.
Solución: Alertar sobre MemAvailable, actividad de swap, fallos mayores y eventos OOM. Enseña a tu equipo a leer free correctamente.
2) Síntoma: “Limpiar cachés lo arregló” (temporalmente)
Causa raíz: Flusheaste page cache y slab, lo que redujo la memoria usada, pero también destruiste rendimiento y enmascaraste el crecimiento real.
Solución: No uses drop_caches como rutina. Si debes usarlo durante diagnóstico, documéntalo y mide el impacto en rendimiento inmediatamente después.
3) Síntoma: kills por OOM pero el host tiene “memoria libre”
Causa raíz: Se alcanzó el límite de cgroup/contenedor. La memoria del host es irrelevante para ese límite.
Solución: Inspecciona memory.max/memory.current, sube límites y establece requests/limits sensatos. Haz alertas de OOM de cgroup distintas de OOM de host.
4) Síntoma: picos de latencia con RAM de sobra
Causa raíz: Thrash de reclaim o stalls por THP/compaction. La memoria “available” puede estar bien en promedio pero no en la forma correcta.
Solución: Revisa fallos mayores, estadísticas de reclaim y ajustes de THP. Considera desactivar THP para cargas sensibles a latencia cuando perjudique.
5) Síntoma: Se usa swap, cunde el pánico
Causa raíz: El uso de swap no es inherentemente malo; lo malo es swap-in/out constante. Linux puede mover páginas frías al swap por política.
Solución: Observa vmstat si/so y fallos mayores. Si está estable, está bien. Si hay churn, trátalo como presión.
6) Síntoma: La memoria crece después de cada deploy y luego “se estabiliza”
Causa raíz: Comportamiento de warmup (JIT, caches, pools de conexión) parece fuga si solo miras la primera hora.
Solución: Compara el estado estable después del warmup. Alerta sobre tasa de crecimiento, no solo nivel, y anota los deploys.
7) Síntoma: “La memoria usada” sube con cargas intensivas en filesystem
Causa raíz: Crecimiento de slab (dentry/inode) bajo churn de metadatos.
Solución: Confirma con slabtop. Reduce el churn (menos archivos, lotes más grandes), afina con cuidado y asegura kernels actualizados.
8) Síntoma: Nodo de base de datos “se come toda la RAM”
Causa raíz: Buffer cache de la BD + caché del OS doble-cacheando, o uso intencional de RAM para rendimiento.
Solución: Dimensiona cachés de BD intencionalmente y deja margen para OS y otros servicios. No coloques servicios hambrientos de memoria juntos sin presupuestos explícitos.
Listas de verificación / plan paso a paso (preparado para producción)
Checklist A: Cuando te pagerán por “memoria alta”
- Ejecuta
free -h. Fíjate enavailable, no en “used.” - Ejecuta
vmstat 1 10. Buscasi/sosostenidos ywaalto. - Busca eventos OOM:
journalctl -k -S -2h | egrep -i 'oom|killed process'. - Si estás en contenedores, revisa cgroup:
memory.currentvsmemory.max. - Si la presión es real, identifica consumidores top (
ps) y verifica crecimiento en 5–15 minutos. - Elige mitigación: limitar cachés, reducir concurrencia, shed de carga, subir límites o añadir RAM.
- Sólo entonces, considera reiniciar—y trátalo como parche temporal con un ticket adjunto.
Checklist B: Estabilizar un host bajo presión de memoria (sin hacer algo de lo que te arrepientas)
- Detén la hemorragia: reduce tráfico/concurrencia o revierte el cambio que aumentó memoria.
- Protege el kernel: asegúrate de tener algo de swap configurado sensatamente y no en medios muy lentos; evita apagar swap como reflejo.
- Prioriza servicios críticos: ajusta prioridades/límites de cgroup para que la base de datos no muera para salvar un job batch.
- Mide el reclaim: fallos mayores,
pgscan,pgstealy churn de swap te dicen si estás thrasheando. - Haz un cambio a la vez: subir un límite de caché y bajar concurrencia en el mismo minuto destruye tu capacidad de razonar.
Checklist C: Construir mejores alertas para que esto no vuelva a pasar
- Alerta por bajo MemAvailable sostenido (host) y memory.current cerca de memory.max (cgroup).
- Alerta por swap-in/out sostenido, no por “swap usado”.
- Alerta por OOM kills como eventos de página con contexto claro de víctima/causa raíz.
- Monitorea procesos top por RSS y su pendiente tras deploys.
- Anota deploys y cambios de configuración en las gráficas de memoria.
Broma #2: “Simplemente aumentaremos el caché” es el equivalente técnico de “me aflojaré el cinturón” — funciona hasta que intentas correr.
Una cita para tener en la pared (o al menos en el runbook)
Idea parafraseada de Gene Kranz (mission operations): “Duro y competente” — mantente calmado, apégate a los fundamentos y ejecuta la lista de verificación.
Preguntas frecuentes
1) ¿Por qué Linux usa casi toda la RAM aun cuando parece que no hay nada corriendo?
Porque “no hay nada corriendo” raramente es cierto (daemons, cachés, estructuras del kernel), y porque Linux usa RAM sobrante para page cache. Esa caché acelera lecturas futuras y se reclama bajo presión.
2) ¿Es malo que el swap sea distinto de cero?
No automáticamente. Uso estable de swap puede significar que páginas frías fueron movidas. Lo malo es swap-in/out sostenido (vmstat si/so), fallos mayores en aumento y latencia visible para usuarios.
3) ¿Cuál es la forma más rápida de distinguir caché de fuga?
Empieza con free: si available está sano, probablemente sea caché. Luego confirma con /proc/meminfo: alto Cached con AnonPages estable apunta a caché; AnonPages en aumento apunta a crecimiento de memoria de procesos.
4) ¿Por qué el mismo servicio usa más RAM con el tiempo sin tener una fuga?
Caches calientes, JIT (Java), comportamiento del asignador (arenas de glibc), pools de conexión y cambios en la carga pueden aumentar la memoria en estado estable. La pregunta es si se estabiliza y si las señales de presión permanecen calmadas.
5) En Kubernetes, ¿por qué me OOMKilled si el nodo tiene memoria libre?
Porque el pod alcanzó su límite de memoria. El kernel aplica los límites de cgroup; no le importa que el nodo tenga margen. Arregla dimensionando requests/limits y/o reduciendo cachés en el contenedor.
6) ¿Debo ejecutar alguna vez echo 3 > /proc/sys/vm/drop_caches en producción?
Casi nunca. Es una herramienta de diagnóstico en el mejor de los casos, y puede causar una caída súbita de rendimiento forzando lecturas de disco que antes eran aciertos de caché. Si lo haces, hazlo intencionalmente, durante investigación controlada y esperando impacto.
7) ¿Y ZFS ARC—es fuga o caché?
Normalmente caché. ARC se expandirá para usar RAM disponible a menos que lo limites. Si ARC compite con aplicaciones verás presión: bajo MemAvailable, swap y reclaim. Soluciona dimensionando ARC y dejando margen.
8) ¿Por qué “available” difiere de “free”?
free es literalmente páginas no usadas en ese momento. available estima la memoria que se puede asignar sin swapear, reclamando caché y otros reclamables. Es el número más útil operativamente.
9) ¿Cómo decido entre “añadir RAM” y “arreglar la app”?
Si estás bajo presión ahora, añadir RAM (o subir límites) puede ser la mitigación menos riesgosa inmediata. Pero si el RSS crece sin límite, más RAM solo retrasa el fallo. Usa la tendencia de crecimiento junto con señales de presión para decidir.
10) ¿El crecimiento de slab del kernel puede causar outages?
Sí. Slab puede consumir grandes cantidades de RAM, especialmente con churn de metadatos de sistemas de archivos o tablas de red. Confírmalo con slabtop e investiga el patrón de carga y la versión del kernel antes de tocar perillas.
Conclusión: pasos prácticos siguientes (haz esto, no vibras)
- Arregla tu modelo mental: deja de tratar “RAM usada” como “RAM no disponible.” Usa
MemAvailabley los indicadores de presión. - Mejora tus alertas: pagina por OOM kills, churn sostenido de swap y baja memoria disponible—no por “used %”.
- Clasifica la memoria: anónima vs caché de archivos vs slab vs cgroup. Elige herramientas que coincidan con la clase.
- Mide tendencias: las instantáneas mienten. Rastrea procesos top por RSS y sus pendientes tras despliegues.
- Haz presupuestos de memoria explícitos: cachés (BD, JVM, Redis, ZFS ARC) necesitan margen. Si no puedes explicar el presupuesto, estás apostando.
- Usa reinicios con moderación: son aceptables como parche temporal cuando la presión es aguda, pero solo si abres la investigación del “por qué creció”.
Si operas sistemas de producción el tiempo suficiente, verás ambos: máquinas con RAM “llena” perfectamente sanas y pequeñas fugas silenciosas que te comen los fines de semana. La diferencia es si buscas señales de presión y atribución—o simplemente miras un porcentaje e inventas una historia.