MemoryError aparece cuando Python no puede completar una asignación de memoria. Puede ocurrir al cargar un archivo enorme, crear una lista gigantesca, duplicar un DataFrame, construir una cadena demasiado grande o ejecutar un algoritmo que conserva más datos de los necesarios. El error no siempre significa que el equipo tenga poca RAM: también puede indicar una estrategia de procesamiento ineficiente.
Qué significa MemoryError
Python lanza esta excepción cuando una operación solicita memoria y el proceso no puede obtenerla. La causa puede estar en la RAM disponible, los límites del sistema, un contenedor, la arquitectura del intérprete o el tamaño de los objetos. La documentación oficial de MemoryError describe la excepción dentro de la jerarquía de errores incorporados.
Primer diagnóstico
Antes de modificar el código, identifica la línea que falla y el tamaño real de la entrada. Comprueba si el programa procesa miles, millones o cientos de millones de elementos. También revisa si crea copias temporales. Un error frecuente es asumir que una operación trabaja “en el lugar” cuando en realidad produce un objeto nuevo.
Si el consumo crece de forma continua durante horas, puede existir una retención de objetos. En ese caso, revisa la guía para detectar fugas de memoria en Python.
Evitar listas gigantes
Una lista almacena referencias a todos sus elementos. Crear una lista completa solo para recorrerla una vez desperdicia memoria.
# consume memoria proporcional al tamaño
numeros = [i * i for i in range(100_000_000)]
# produce valores bajo demanda
numeros = (i * i for i in range(100_000_000))
for numero in numeros:
procesar(numero)El generador no guarda todos los resultados. Para comprender mejor el costo de las colecciones, consulta la guía de listas en Python.
Procesar archivos por líneas
No utilices read() para archivos enormes si puedes iterar:
with open("registro_grande.txt", encoding="utf-8") as archivo:
for linea in archivo:
procesar(linea)La iteración mantiene una parte pequeña en memoria. Para CSV también puedes usar el módulo csv y procesar fila por fila.
Trabajar por lotes
Cuando una biblioteca necesita colecciones, divide la entrada:
def lotes(iterable, tamano):
lote = []
for elemento in iterable:
lote.append(elemento)
if len(lote) == tamano:
yield lote
lote = []
if lote:
yield loteDespués procesa y descarta cada lote. El tamaño ideal depende de la memoria, el costo de entrada y salida y la biblioteca utilizada.
Pandas y archivos grandes
Un DataFrame puede consumir varias veces el tamaño del archivo original debido a índices, tipos de datos y objetos temporales. Utiliza chunksize:
import pandas as pd
for bloque in pd.read_csv("ventas.csv", chunksize=50_000):
resumen = bloque.groupby("categoria")["total"].sum()
guardar_resumen(resumen)También especifica usecols para cargar solo columnas necesarias y dtype para evitar tipos demasiado grandes.
Reducir tipos numéricos
Un entero de 64 bits puede ser innecesario para valores pequeños. En NumPy o Pandas, convertir a int32, int16 o float32 puede reducir memoria. Hazlo únicamente después de comprobar rangos y precisión; una conversión incorrecta puede desbordar o alterar resultados.
Eliminar copias innecesarias
Operaciones como concatenaciones repetidas, filtros encadenados y conversiones pueden crear copias. En cadenas, evita sumar miles de fragmentos:
partes = []
for elemento in elementos:
partes.append(transformar(elemento))
resultado = "".join(partes)Para volúmenes extremos, escribe directamente en un archivo o usa un flujo en vez de guardar todas las partes.
Liberar referencias grandes
Cuando un objeto ya no se necesita, permite que salga de alcance o elimina la referencia:
datos = cargar_datos()
procesar(datos)
del datosdel no garantiza que el sistema operativo reciba la memoria inmediatamente, pero elimina esa referencia. Si otras estructuras siguen apuntando al objeto, continuará vivo.
Medir con tracemalloc
Para descubrir las líneas que asignan más memoria:
import tracemalloc
tracemalloc.start()
ejecutar_proceso()
actual, pico = tracemalloc.get_traced_memory()
print(f"Actual: {actual / 1024**2:.2f} MB")
print(f"Pico: {pico / 1024**2:.2f} MB")La documentación de tracemalloc incluye snapshots y comparaciones más detalladas.
Separar el problema en funciones
Un programa dividido en funciones pequeñas facilita medir el consumo por etapa y soltar referencias al terminar. La guía de funciones en Python explica cómo organizar responsabilidades y retornos.
No capturar el error sin corregir la causa
Este patrón rara vez ayuda:
try:
crear_objeto_enorme()
except MemoryError:
print("No hay memoria")Capturar la excepción puede servir para guardar estado o mostrar un mensaje, pero volver a ejecutar la misma estrategia producirá el mismo resultado. La solución es reducir la asignación, dividir el trabajo o cambiar el algoritmo.
Revisar el algoritmo
Algunos algoritmos guardan matrices, combinaciones o historiales que crecen de forma cuadrática o exponencial. Antes de comprar más RAM, pregunta si realmente necesitas conservar todos los resultados. Procesar, resumir y descartar suele ser mejor que acumular.
Contenedores y límites
Docker, Kubernetes y plataformas de alojamiento pueden limitar la memoria aunque el servidor tenga más RAM. Revisa la configuración del contenedor y las métricas del proceso. Aumentar el límite puede ser necesario, pero primero confirma que el consumo esperado sea razonable.
Rendimiento y memoria
Menos memoria también puede mejorar velocidad al reducir copias y presión sobre la caché. Sin embargo, no optimices a ciegas. Utiliza cProfile para medir tiempo y herramientas de memoria para asignaciones. Son problemas relacionados, pero no idénticos.
Buenas prácticas
Lee datos de forma incremental, utiliza generadores, limita cachés, selecciona columnas, define tipos adecuados y mide el pico. Prueba con una entrada representativa antes de producción. Si una operación necesita más memoria que la disponible incluso después de optimizar, considera procesamiento distribuido, una base de datos o almacenamiento temporal en disco.
MemoryError es una señal concreta: una asignación superó la capacidad disponible. Al convertir operaciones masivas en flujos y lotes, la mayoría de los programas puede procesar datos mucho mayores sin necesitar mantenerlos completos en RAM.






