¿Ver la memoria RAM disponible?

Hola a todos. Hace tiempo tenía yo esta pregunta: ¿existe algún pedazo de código, función o librería; que me muestre (o devuelva) la cantidad de memoria RAM disponible en tiempo de ejecución?

Es que he hecho un programa reproductor de archivos WAV, pero con algunas extras; y el compilador ya me tiene amenazado de que hay poco espacio en la memoria RAM para la ejecución.

El programa funciona bien a pesar de eso, lo que pasa es que quisiera saber cuanta memoria disponible queda en ciertos momentos de la ejecución.

Espero haberme explicado bien el problema y agradecería de antemano cualquier respuesta...

Lucario eres muy activo entonces mas que muchos, usa google: Arduino memory free o arduino memory available

Available Memory

surbyte:
Lucario eres muy activo entonces mas que muchos

Lo sé jaja. Lo que pasa es que esto de ayudar en los foros de Arduino lo empiezo a ver como una "diversión"; por eso es que paso demasiado activo.

usa google: Arduino memory free o arduino memory available

Solo mírame. Me emocioné tanto con esto, que ya olvidé lo que es buscar en Google. Mis disculpas por eso. :sweat_smile:

Quiero compartirles lo que encontré:

Arduino Playground - AvailableMemory (está en inglés)

Descargué la librería, y es tan sencillo de usar como importarla y llamar a la función freeMemory(), la cual devuelve un int.

De nuevo, me disculpo si los hice gastar tiempo innecesariamente... :sweat_smile: :roll_eyes:

Pero que encontraste si te lo di servido en bandeja jajajaja
Ademas un search en este foro te hubiera dado la misma respuesta. Lo hemos respondido muchas veces

surbyte:
Pero que encontraste si te lo di servido en bandeja jajajaja

¡¡¡Definitivamente que sí!!! :smiley:

Ademas un search en este foro te hubiera dado la misma respuesta. Lo hemos respondido muchas veces

Seguro que sí. En esa página dice que el código de la librería está basado, de hecho, en una discusión hecha en un hilo de un foro de este sitio web. Por lo tanto, ¡estás en lo cierto!

Lucario448:
Quiero compartirles lo que encontré:

Arduino Playground - HomePage (está en inglés)

Descargué la librería, y es tan sencillo de usar como importarla y llamar a la función freeMemory(), la cual devuelve un int.

De nuevo, me disculpo si los hice gastar tiempo innecesariamente... :sweat_smile: :roll_eyes:

Si seguiste leyendo el artículo del playground, habrás visto que además de la librería hay otros modos. Yo, particularmente me quedaría con el último por su simplicidad. Sencillamente incluir esta función, que devuelve la memoria disponible:

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

Para los curiosos, explico un poco los fundamentos (espero no resultar cargante).

La gestión de la memoria se realiza en dos zonas:

  • Heap o montón, que está ubicado al principio de la memoria, donde se guardan las variables globales y las creadas mediante asignación dinámica de memoria (calloc, malloc, new...). Va creciendo hacia arriba a medida que "amontonamos" cosas en ella. El puntero __brkval almacena la posición de su "cima".
  • Stack o pila, que está ubicada al final de la memoria, y es donde se crean las variables locales de las funciones, y el valor devuelto por éstas. Crece hacia abajo el espacio necesario para depositar sus variables cuando se llama a una función, y decrece al salir de ésta.
    Entonces, cuando llamamos a la función de arriba, su variable local v se ubica en la "punta" de la pila. Restando de la posición de la punta de la pila (&v) la posición de la cima del montón (__brkval) tendremos el tamaño del "hueco" entre ambos, que viene a ser la memoria disponible.
    Sólo quedaría un fleco, que serían los huecos que pueden quedar en el montón al liberar memoria dinámica y ser reutilizados en nuevas asignaciones, y con la que no puedes contar alegremente, pues no se tratará de un espacio continuo, sino de fragmentos. Por ello, si de lo que se trata es de saber si estamos en apuros de memoria, podemos obviar estos huecos.

noter muchas gracias por tu explicación. Entonces... no es del todo 100% precisa la medición?

Resulta que me preocupa el uso de la memoria RAM, porque por errores difíciles de encontrar en un código (y no detectados por el compilador); he provocado, en múltiples ocasiones, que el programa se me "colgara" por memoria llena. Y me interesa mucho este tema, para agregar más características de depuración...

Eso ocurre uando Strings y no poniendolos a 0 de tanto en tanto.
O si usas punteros.
cual de las dos formas usas?

surbyte:
Eso ocurre uando Strings y no poniendolos a 0 de tanto en tanto.
O si usas punteros.
cual de las dos formas usas?

Sospecho que en realidad fue por no cerrar archivos (en una función que enlistaba los archivos de una carpeta). Cuando digo "archivos", hablo de la clase File de la librería SD. Ese problema costó demasiado encontrarlo, debido a la incapacidad de poder mostrarme la memoria disponible en tiempo de ejecución.

La clase String, más bien, me da miedo utilizarla por eso mismo.

La medición te proporciona el hueco principal disponible. Puede ser que dispongas además de fragmentos que hayan ido quedando, pero esos fragmentos no valen para la pila ni en su conjunto para el montón. Sólo se puede utilizar un hueco para asignación dinámica y si es de tamaño suficiente para la variable que queramos guardar. Por ello decía que no podemos contar con esos huecos. Lo que sí es claro es que si esa función te reporta muy poco espacio lo más probable es que tengas problemas. Puede darse la paradoja de disponer de un montón de espacio en huecos en el montón, pero si el hueco entre las cimas de pila y montón es pequeño, una llamada a función puede hacer que se pisen. Por ello digo que la información que reporta la función es la importante, pues el posible espacio extra no sirve para uso general.

noter:
La medición te proporciona el hueco principal disponible. Puede ser que dispongas además de fragmentos que hayan ido quedando, pero esos fragmentos no valen para la pila ni en su conjunto para el montón. Sólo se puede utilizar un hueco para asignación dinámica y si es de tamaño suficiente para la variable que queramos guardar. Por ello decía que no podemos contar con esos huecos. Lo que sí es claro es que si esa función te reporta muy poco espacio lo más probable es que tengas problemas. Puede darse la paradoja de disponer de un montón de espacio en huecos en el montón, pero si el hueco entre las cimas de pila y montón es pequeño, una llamada a función puede hacer que se pisen. Por ello digo que la información que reporta la función es la importante, pues el posible espacio extra no sirve para uso general.

Dos preguntas:

  • Los fragmentos de variables antiguas (creadas por funciones que ya acabaron) y objetos destruidos entonces siguen contando como espacio libre?
  • Pila y montón comparten memoria? Dicho en otras palabras: estos no tienen un espacio fijo?

Lucario448:
Los fragmentos de variables antiguas (creadas por funciones que ya acabaron) y objetos destruidos entonces siguen contando como espacio libre?

En la versión librería creo que ambas. En la versión función lo único que no cuenta son los huecos que pueden quedar de objetos destruidos; memoria que, por otra parte, sólo se puede utilizar por nuevos objetos, no por variables temporales, y sólo si el nuevo objeto cabe en uno de esos huecos. Por ello no es totalmente "memoria libre".

Lucario448:
Pila y montón comparten memoria? Dicho en otras palabras: estos no tienen un espacio fijo?

A grandes rasgos, la organización de memoria viene a ser la siguiente:

  • Espacio ocupado por variables globales. El espacio que ocupan es fijo, y no hay huecos. La vida de las variables es "eterna".
  • Espacio ocupado por el montón. La vida de estas variables depende de la programación. Las creamos y las "matamos" a voluntad, dejando huecos cuando la variable eliminada no está en la cima del montón. Cuando creamos una nueva variable de montón, puede ocupar un hueco dejado por una variable eliminada de montón, o si no hay hueco suficiente, ir a la cima del montón, invadiendo parte de la memoria libre principal por su parte "inferior".
  • Memoria libre principal. La que cuenta la función. Desde la cima del montón hasta la cabecera de la pila.
  • Pila de programa. Comienza desde la posición final de memoria, creciendo hacia "abajo". Las variables temporales de las distintas funciones se depositan, haciendo crecer hacia abajo la pila, invadiendo la memoria libre principal por su parte superior. Como las llamadas y retornos a función son ordenados (salimos primero de la última función llamada) la pila crece y decrece sin dejar huecos.

El problema de falta de memoria se produce cuando intenta crecer la pila o el montón ocupando más allá del espacio principal disponible (stack overflow o heap overflow), y eso se puede producir independientemente del número de huecos que tengamos en el montón, cuando la cima de éste y la cima de la pila se tocan.

Muy bien señores; muchísimas gracias por sus respuestas :smiley:
¡Ahora todo me quedó claro!

No sé que opinan uds, pero yo pienso que a pesar de que no se puedan tomar en cuenta los agujeros en el montón ("heap"), considero que el método de medición de memoria libre sigue siendo útil para saber en qué momento el programa corre el peligro de "colgarse".

Ah y una cosa más. Estaba indagando, pero no tengo una respuesta clara de cómo hacerlo, quizá y me puedas ayudar.
Es que quiero "visualizar" como se va llenando la memoria RAM. Para esto, quisiera saber si es posible hacer un volcado de memoria y guardarlo en una tarjeta SD. Supongo que para eso tengo que paralizar la ejecución del programa; entonces, SPI podrá seguir funcionando dentro de una ISR?

Una vez más, ¡gracias!

Es lo que te vengo diciendo desde el principio: Creo que la librería sí te da la memoria disponible incluyendo los huecos, pero podría darse la paradoja de tener un montón de espacio fragmentado y estar mucho más cerca de la catástrofe de lo que pensamos. Por ello recomiendo la función (además de que es más liviana que la librería) si lo único que queremos es ver si estamos en peligro.
En cuanto a visualizar cómo se va llenando la RAM, yo me decantaría más por la simulación. Por ejemplo en proteus puedes simular arduino, y depurar, visualizando memoria, registros, etc.

Proteus no se si me funcionará para algo de poco uso, ya que como no es un programa gratuito...

Verdad que el programa de Arduino no verifica los límites de un "array"?

Porque de ser así, podré crear un "objeto" que guarde un "array" de 1 de longitud? Como hacer que ese objeto se guarde lo más al principio de la memoria?

Mi idea es hacer un volcado (aunque sea) parcial de memoria, con un desbordamiento intencional del "array". Será buena idea?

No entiendo muy bien por dónde quieres ir.
Con un puntero podrías escudriñar cualquier posición de memoria. Lo que pasa es que tarde o temprano los resultados de salida estarán tergiversados, porque llegarás precisamente a las posiciones de memoria donde se están moviendo los datos de la rutina que se esté ejecutando.

Por ejemplo, podrías hacer algo así:

void vuelcaMemoria(){
	byte *posmem = 0;
	do{
	    Serial.print((int) posmem, HEX);
	    Serial.print(" - ");
	    Serial.println(*posmem++, HEX);
	} while ((int)posmem < 0x500);
	
}

Pero sigo sin saber exactamente qué quieres comprobar.

noter:
Con un puntero podrías escudriñar cualquier posición de memoria.

Bueno... no tenía idea que un puntero que no apunte (valga la redundancia) directamente a un "array", puede apuntar a cualquier punto de la memoria.

No entiendo muy bien por dónde quieres ir.

Tengo curiosidad de ver como se va llenando la memoria. Decía yo, volcarla a un archivo para crear una especie de "captura" ("snapshot") de la memoria en ese preciso momento.

Lo que pasa es que tarde o temprano los resultados de salida estarán tergiversados, porque llegarás precisamente a las posiciones de memoria donde se están moviendo los datos de la rutina que se esté ejecutando.

Supongo que eso lo puedo solventar paralizando la ejecución del programa, cierto?
Por eso además preguntaba que si SPI puede funcionar durante una ISR.

Y para usar SPI que requieres? SRAM entonces.. el huevo y la gallina lucario, que verás, la foto del momento que quiera retratar.

preguntaba que si SPI puede funcionar durante una ISR.

Una ISR de que tipo? plantea mejor el contexto.

Tal parece que estoy cayendo en los errores de los novatos... :frowning:

surbyte:
Y para usar SPI que requieres?

Interactuar con una tarjeta SD. O de que otra forma podría guardar el volcado en un archivo?

que verás, la foto del momento que quiera retratar.

Esta parte no la entendí...

Una ISR de que tipo? plantea mejor el contexto.

Una interrupción... externa? No sé como se llama cuando es desencadenada por un botón.