Memory Expansion

⚡ Definición Rápida
Memory Expansion (expansión de memoria) es el costo dinámico en gas que la Máquina Virtual de Ethereum (EVM) cobra cuando un contrato inteligente necesita utilizar más memoria RAM de ejecución de la que ya tenía asignada. Este costo sigue una fórmula cuadrática: cuanto más lejos de la memoria ya usada se expande el contrato, más caro resulta cada nueva palabra de 32 bytes. Este mecanismo sirve para desincentivar el uso excesivo de memoria y prevenir ataques de denegación de servicio (DoS) que podrían congestionar a los nodos validadores.
Términos relacionados: Gas • EVM • Gas Limit • Gas Price • Bytecode
❓ ¿Qué es la Memory Expansion y por qué su costo es crucial para Ethereum?
La Memory Expansion es un concepto fundamental en la economía del gas de Ethereum. La EVM no asigna de antemano toda la memoria que un contrato podría potencialmente usar. En su lugar, empieza con una memoria «vacía» y la expande según sea necesario. Para garantizar que la red siga siendo segura y predecible, el protocolo debe penalizar a los contratos que realicen expansiones de memoria grandes y «saltos» desordenados en el espacio de direcciones de memoria.
Un atacante podría, en teoría, escribir un contrato que pida memoria en posiciones muy distantes entre sí, forzando a los nodos a preparar y gestionar grandes espacios de memoria de forma desordenada, ralentizando la validación. La fórmula cuadrática actúa como un dique de contención económico. Hace que un acceso pequeño y secuencial a la memoria sea barato (ideal para operaciones legítimas), mientras que un patrón de acceso errático y amplio se vuelve prohibitivamente caro.
Comprender y optimizar este costo es fundamental para desarrollar contratos eficientes, especialmente aquellos que manejan arrays dinámicos, concatenación de strings en Solidity o cálculos complejos. Es tan crucial para el control del gasto en gas como optimizar el storage.
📖 Definición Técnica
La EVM gestiona la memoria en palabras (words) de 32 bytes. Lleva un registro de la «palabra de memoria más alta» (`memory_pointer`) que se ha utilizado hasta el momento. Cada vez que una operación (como `MSTORE`, `MLOAD`, o la creación de un array dinámico en memoria) necesita acceder a una dirección de memoria, la EVM comprueba si esa dirección está más allá del `memory_pointer` actual. Si lo está, se produce una expansión de memoria.
El costo en gas para expandir la memoria se calcula mediante la fórmula:
Costo_total_de_memoria = (new_mem_size_in_words^2 / 512) + (3 * new_mem_size_in_words) – memoria_cost_hasta_ahora
Donde `memoria_cost_hasta_ahora` es el costo acumulado calculado con la misma fórmula para el tamaño anterior. En la práctica, el costo marginal de expandir una palabra adicional se va haciendo más grande.
⚙️ Memoria vs. Storage vs. Calldata: Costos de Expansión
La confusión sobre qué tipo de datos usar es una de las mayores fuentes de ineficiencia en contratos inteligentes. Aquí se establece una comparación clara.
| Aspecto | Memory (Memoria) | Storage (Almacenamiento) | Calldata |
|---|---|---|---|
| Costo de Expansión | Dinámico y Cuadrático. Depende de la nueva «palabra de memoria» más alta utilizada. | Fijo por Slot. ~20,000 gas para una primera escritura, ~2,900 para una modificación. | No aplica. Es de solo lectura, su tamaño es fijo por la transacción. |
| Fórmula (Aprox.) | Gas = (nuevas_palabras^2 / 512) + (3 * nuevas_palabras) | Gas = Costo fijo definido en el EIP-3529 y otros. | Gas = 4 gas por byte cero, 16 gas por byte no cero (en llamadas externas). |
| Persistencia | Temporal (dura solo la ejecución de la llamada). | Permanente (en la blockchain). | Temporal y de solo lectura (datos de entrada). |
| Uso Típico | Arrays temporales, variables dentro de funciones, cálculos intermedios. | Estado del contrato, datos permanentes. | Parámetros de funciones, especialmente en llamadas externas. |
| Riesgo de DoS | Alto sin el costo cuadrático. Un contrato podría pedir gigas de memoria. | Limitado por el costo fijo alto. Llenar el storage es muy caro. | Muy limitado. El tamaño máximo está acotado por el gas limit de la transacción. |
🏗️ Cómo se calcula el costo: La fórmula paso a paso
El cálculo no es intuitivo, pero entenderlo es clave para la optimización. Aquí se desglosa en pasos concretos.
1. Identificar la nueva palabra más alta:
Cada vez que una operación (como `MSTORE`, `MLOAD`, o la creación de un array dinámico en memoria) necesita acceder a una dirección de memoria, la EVM comprueba si esa dirección está más allá del `memory_pointer` actual. Si lo está, se produce una expansión de memoria.
2. Aplicar la fórmula cuadrática:
El costo en gas para expandir la memoria desde el puntero antiguo (`old_mem_size_in_words`) al nuevo (`new_mem_size_in_words`) se calcula así:
Costo_total_de_memoria = (new_mem_size_in_words^2 / 512) + (3 * new_mem_size_in_words) – memoria_cost_hasta_ahora
Donde `memoria_cost_hasta_ahora` es el costo acumulado calculado con la misma fórmula para el tamaño anterior. En la práctica, el costo marginal de expandir una palabra adicional se va haciendo más grande.
3. Ejemplo concreto y numérico:
Imagina un contrato que no ha usado memoria. Su `memory_pointer` es 0.
Paso 1: Escribe un `uint256` en la posición `0x60` (que corresponde a la palabra 3 en decimal, porque `0x60` / `0x20` = 3).
* `new_mem_size = 4` (porque las palabras se indexan desde 0, el tamaño es el máximo índice + 1).
* Costo = `(4^2 / 512) + (3*4) – 0 = (16/512) + 12 ≈ 0.03125 + 12 = ~12.03 gas` (muy barato).
Paso 2: Luego, necesita escribir en la palabra 1000.
* `new_mem_size = 1001`.
* Costo total hasta ahora = `(1001^2 / 512) + (3*1001) ≈ (1,002,001/512) + 3003 ≈ 1957 + 3003 = 4960 gas`.
* Pero ya pagamos ~12 gas en el Paso 1.
El costo marginal de este salto grande es: `4960 – 12 = ~4948 gas`.
Conclusión: Saltar a la palabra 1000 de golpe costó ~4948 gas, mientras que haber escrito secuencialmente hasta allí (palabra por palabra) habría costado muchísimo más en total. El sistema incentiva un uso compacto y secuencial de la memoria.
Recurso técnico: Para los detalles exactos de la implementación en los clientes de Ethereum, puedes consultar el código fuente de la EVM en el repositorio de Execution Specifications o el «Yellow Paper» de Ethereum.
🎯 Optimización práctica: Cómo evitar costos excesivos de memoria
Los desarrolladores pueden seguir varias estrategias para minimizar el impacto de la memory expansion en sus contratos.
1. Usar `calldata` en lugar de `memory` para parámetros de arrays/bytes:
En funciones `external`, especifica los parámetros de arrays y bytes como `calldata` en lugar de `memory`. Esto evita por completo la costosa copia de datos a la memoria de la EVM, ya que la función leerá directamente de los datos de la transacción, que son mucho más baratos de acceder. Es una de las optimizaciones más sencillas y efectivas.
2. Dimensionar arrays en memoria de forma realista:
Cuando crees un array dinámico en memoria (`new uint256[]`), si conoces el tamaño de antemano, especifícalo en la declaración. Esto permite que la EVM asigne el espacio de memoria de una vez de manera más eficiente, en lugar de ir redimensionando el array con cada `push`, lo que puede provocar múltiples expansiones costosas.
3. Reutilizar arrays en memoria:
Si una función necesita arrays temporales para cálculos intermedios que se llaman múltiples veces dentro de un bucle, considera declarar el array fuera del bucle y reutilizarlo (limpiándolo si es necesario), en lugar de crear una nueva instancia en cada iteración, lo que dispararía los costos.
4. Evitar la concatenación de strings en memoria dentro de la cadena:
Operaciones como `string(abi.encodePacked(a, b))` crean nuevos bytes en memoria. Si se hacen en un bucle, el costo de expansión de memoria puede volverse cuadráticamente grande. En su lugar, calcula el tamaño final necesario primero, o realiza estas operaciones off-chain si es posible.
5. Ejemplo: Llamada ABI Decoding Eficiente
Un contrato que actúa como un proxy o un router a menudo decodifica datos de llamadas.
Ineficiente: `(uint256 a, address b) = abi.decode(_data, (uint256, address));` (decodifica a `memory` por defecto).
Eficiente: `(uint256 a, address b) = abi.decode(_data, (uint256, address));` // Si `_data` es `calldata`, la decodificación puede ser más eficiente en versiones recientes de Solidity. Mejor aún, acceder a los datos directamente con `assembly` para evitar copias intermedias si el gas es crítico.
⚖️ Ventajas del modelo y errores comunes
✅ Ventajas del Modelo Cuadrático:
- Protección contra DoS: Hace económicamente inviable atacar a los nodos pidiendo cantidades masivas de memoria de forma desordenada.
- Incentiva Buenas Prácticas: Fomenta un uso compacto y secuencial de la memoria, que es más eficiente para que la EVM gestione.
- Predecibilidad Relativa: Para operaciones normales (memoria compacta), el costo es bajo y predecible. Solo se dispara en patrones anómalos.
⚠️ Errores Comunes y Cómo Evitarlos:
- Confundir `memory` con `storage` o `calldata`: Usar `memory` por defecto para grandes arrays en parámetros de función es un error costoso. Siempre pregunta: ¿Estos datos vienen de fuera? Usa `calldata`. ¿Persisten? Usa `storage`.
- No dimensionar arrays dinámicos en memoria: Dejar que crezcan con `.push()` en un bucle puede generar un costo de expansión sorprendentemente alto. Siempre que sea posible, inicializa con el tamaño.
- Ignorar el costo en funciones llamadas frecuentemente: Una función que es barata al ser llamada una vez puede ser muy cara si se llama miles de veces en una transacción (por ejemplo, en un bucle interno de un contrato complejo). Perfila el gas de tus contratos en diferentes escenarios.
🔮 El futuro: ¿Cambiará el modelo de costo de memoria?
El modelo cuadrático ha demostrado ser robusto, pero el ecosistema Ethereum siempre evoluciona hacia una mayor eficiencia.
- Mejoras en la EVM (EOF): La EVM Object Format (EOF) introduce una gestión más estricta y eficiente del código y, potencialmente, de los recursos de ejecución como la memoria. Podría permitir una contabilización del gas aún más precisa y optimizada.
- Enfoque en la Experiencia del Desarrollador: Mejores herramientas de desarrollo, depuradores y profilers de gas integrarán estimaciones más claras del costo de memoria, ayudando a los desarrolladores a identificar puntos de expansión innecesarios más fácilmente.
- Optimizaciones de Larga Data: El principio fundamental (desincentivar el uso errático y grande de memoria) es probable que permanezca. Cualquier cambio en la fórmula buscaría mantener esta seguridad mientras se ajustan los costos para patrones de uso legítimos comunes en aplicaciones modernas, como las que se ejecutan en soluciones de capa 2.
🎯 Conclusión: Un guardián necesario para la salud de la red
Memory Expansion no es un bug ni una complicación arbitraria; es un mecanismo de seguridad criptoeconómica cuidadosamente diseñado. Al imponer un costo cuadrático, asegura que el recurso de la memoria de ejecución, que es escaso y compartido por todos los nodos validadores, no pueda ser abusado. Para el desarrollador, entender este mecanismo es pasar de simplemente escribir código que funciona, a escribir código que es eficiente, seguro y responsable con la red.
En un mundo donde cada gas cuenta, dominar los matices del costo de la memoria, junto con el del storage y el gas general, es lo que separa a un contrato amateur de uno profesional. Es una parte intrínseca del viaje para construir aplicaciones descentralizadas que no solo sean innovadoras, sino también viables y sostenibles a largo plazo en la mainnet de Ethereum.
❓ Preguntas Frecuentes sobre Memory Expansion
📚 ¿Quieres profundizar en desarrollo y optimización?
Explora más recursos de La Cryptoguía sobre Ethereum y desarrollo de contratos inteligentes:
🔗 Gas en Ethereum – El sistema general del que la memory expansion es una parte crítica.
⚡ ¿Qué es Blockchain? – La tecnología subyacente que requiere estos modelos de costos para su seguridad.
🏗️ ¿Qué es DeFi? – Donde la optimización de cada unidad de gas se traduce en mejores productos.
🔐 Guía de Seguridad Crypto – Incluye principios para escribir código eficiente y seguro.
🛠️ Cómo auditar un token – Un proceso donde evaluar el uso de la memoria es un paso clave.
🚀 ¿Empezando en Crypto?
Lee nuestra guía completa gratuita para principiantes y descubre todo lo que necesitas saber para empezar de forma segura.
📋 ¿Por qué confiar en esta definición? Cada término de la Cryptopedia sigue una metodología de verificación con fuentes primarias, whitepapers y legislación oficial. Conoce nuestro proceso →
⚠️ Disclaimer: Este artículo es informativo y educativo. No constituye asesoramiento financiero, legal o técnico. Los costos de gas y el comportamiento de la EVM son complejos y pueden cambiar mediante actualizaciones de protocolo (hard forks). La optimización extrema del gas puede comprometer la legibilidad y seguridad del código. Siempre prueba exhaustivamente en redes de prueba, audita tu código y comprende los trade-offs antes de desplegar contratos en mainnet.
📅 Actualizado: Marzo 2026
📖 Categoría: Infraestructura Blockchain / Ejecución y EVM
