Fuga de memoria en bots de Discord en procesos de larga duración: solución
🔍 WiseChecker

Fuga de memoria en bots de Discord en procesos de larga duración: solución

Si ejecutas un bot de Discord durante horas o días, es posible que notes que su uso de memoria aumenta de forma constante. Esto es una fuga de memoria, donde el bot no libera la memoria que ya no necesita. Con el tiempo, puede ralentizar el bot, provocar fallos o hacer que no responda. Este artículo explica las principales causas de las fugas de memoria en bots de Discord de larga duración y proporciona soluciones concretas para mantener estable el uso de memoria.

Puntos clave: Cómo solucionar una fuga de memoria en un bot de Discord

  • Desactiva los intents predeterminados para miembros del servidor y presencias: Reduce el uso de memoria entre un 30 y un 50 % en bots de larga duración.
  • Añade client.users.cache.clear() en una función de limpieza periódica: Evita que la caché de usuarios crezca sin límite.
  • Usa setInterval para limpiar las cachés de mensajes y canales cada 10 minutos: Mantiene el uso de memoria por debajo de 150 MB incluso después de 24 horas.

ADVERTISEMENT

Por qué los bots de Discord pierden memoria en procesos de larga duración

Discord.js y bibliotecas similares mantienen cachés en memoria para usuarios, mensajes, canales y servidores. En un bot de larga duración, estas cachés crecen a medida que el bot procesa eventos. El tamaño de caché predeterminado es ilimitado. Si tu bot escucha muchos servidores o canales, la caché puede aumentar hasta cientos de MB en pocas horas.

Otra causa son los listeners de eventos que no se eliminan correctamente. Cuando tu bot se suscribe a eventos como messageCreate o guildMemberAdd, la biblioteca almacena referencias a las funciones de callback. Si añades nuevos listeners sin eliminar los antiguos, las referencias se acumulan e impiden la recolección de basura.

Una tercera causa es almacenar objetos grandes en variables globales o colecciones. Por ejemplo, recopilar cada mensaje de un canal en un array sin vaciarlo hará que la memoria crezca linealmente con el tiempo.

Cómo funciona el almacenamiento en caché en Discord.js

Discord.js v13 y v14 usan una clase Collection (que extiende Map) para el almacenamiento en caché. Cuando un usuario envía un mensaje, la biblioteca añade el objeto de usuario a client.users.cache si aún no está allí. Lo mismo ocurre con mensajes, canales y servidores. La caché nunca elimina entradas a menos que llames manualmente a .delete() o .clear().

El papel de los intents

Los intents controlan qué eventos recibe tu bot. Si habilitas el intent GuildMembers, Discord envía actualizaciones de la lista de miembros para cada servidor. Para un bot en 100 servidores con 500 miembros cada uno, eso significa 50 000 objetos de miembro en caché. Deshabilitar los intents que no se usan reduce los datos que tu bot debe almacenar.

Pasos para solucionar una fuga de memoria en un bot de Discord

  1. Desactiva los intents innecesarios
    Abre el código de tu bot y localiza el constructor Client. Elimina GatewayIntentBits.GuildMembers y GatewayIntentBits.GuildPresences a menos que tu bot los necesite específicamente. Estos dos intents causan el mayor consumo de memoria. Después de deshabilitarlos, reinicia el bot y monitoriza el uso de memoria.
  2. Limita el tamaño de la caché de mensajes
    En el constructor Client, establece sweepers: { messages: { interval: 600, lifetime: 1800 } } (Discord.js v14). Esto elimina de la caché los mensajes con más de 30 minutos de antigüedad cada 10 minutos. Para v13, usa messageCacheLifetime: 1800 y messageSweepInterval: 600 en el objeto de opciones.
  3. Limpia la caché de usuarios periódicamente
    Añade una función que se ejecute cada 15 minutos usando setInterval. Dentro de ella, llama a client.users.cache.clear(). Esto elimina todos los objetos de usuario en caché. Haz lo mismo con client.channels.cache y client.guilds.cache si tu bot no necesita mantenerlos en memoria.
  4. Elimina los listeners de eventos que no se usan
    Si tu bot añade listeners de eventos dinámicamente, guarda la referencia y llama a client.removeListener(event, callback) cuando el listener ya no sea necesario. Por ejemplo, si escuchas messageCreate en un canal específico, elimina el listener cuando el bot salga de ese canal.
  5. Usa WeakRef o FinalizationRegistry para datos grandes
    Si tu bot almacena objetos grandes como datos de conexión de voz o datos de usuario personalizados, usa WeakRef para permitir la recolección de basura cuando el objeto ya no tenga referencias. Evita almacenar datos en arrays o mapas globales a menos que los vacíes con regularidad.
  6. Monitoriza la memoria con process.memoryUsage()
    Añade un registro cada 10 minutos que imprima process.memoryUsage().heapUsed. Si el valor aumenta más de un 5 % por hora, hay una fuga. Usa esto para verificar tus soluciones.

ADVERTISEMENT

Si el bot sigue teniendo una fuga de memoria después de la solución principal

El bot se bloquea con un error de memoria insuficiente

Si tu bot se bloquea con un error de memoria insuficiente del heap de JavaScript, aumenta el límite de memoria de Node.js. Ejecuta el bot con node --max-old-space-size=512 bot.js (512 MB). Esto es una solución temporal. La solución real es reducir el tamaño de la caché como se describe arriba.

La memoria crece incluso después de limpiar las cachés

Comprueba si hay referencias circulares. Si tu código crea objetos que se referencian entre sí, no se pueden recolectar como basura. Usa el flag --inspect con Chrome DevTools para tomar instantáneas del heap. Busca objetos con un tamaño retenido grande que no deberían estar ahí.

El bot se ralentiza con el tiempo

Un uso elevado de memoria obliga al recolector de basura a ejecutarse con más frecuencia, lo que bloquea el bucle de eventos. Si tu bot responde lentamente después de horas de actividad, es probable que la fuga de memoria sea grave. Aplica todos los pasos de solución anteriores y reinicia el bot.

Gestión de memoria en bots de Discord: caché manual vs. sweeper vs. base de datos externa

Establecer

Almacenar datos en Redis, consultar bajo demanda

Elemento Limpieza manual de caché Sweeper integrado Base de datos externa (Redis)
Implementación Añadir setInterval con llamadas a .clear() en las opciones del Clientsweepers
Reducción de memoria Reduce el heap entre un 50 y un 70 % Reduce el heap entre un 30 y un 50 % La memoria del bot se mantiene por debajo de 100 MB
Impacto en el rendimiento Pausa breve durante la limpieza Sin pausa perceptible Latencia de red en cada consulta
Persistencia de datos Se pierden al limpiar Se pierden tras el intervalo de barrido Persistentes entre reinicios

Ahora puedes identificar y solucionar fugas de memoria en tu bot de Discord. Empieza por deshabilitar los intents que no uses y configurar un sweeper. Si el problema persiste, añade una limpieza periódica de caché y monitoriza el uso del heap con process.memoryUsage(). Para bots que deben permanecer en línea durante semanas, considera mover los datos persistentes a una base de datos externa como Redis. Esto reduce el uso de memoria del bot casi a cero y evita fallos.

ADVERTISEMENT