Pregunta de C

Daniel Serpell daniel_serpell en yahoo.com
Jue Mayo 11 16:45:04 CLT 2006


Hola!

El Thu, May 11, 2006 at 10:22:10AM -0400, Alvaro Herrera escribio:
> 
> Trate de ver lo que sucedia si ponia un canario abajo y otro arriba de
> la variable, o sea 
> 
> int	canario1 = 0x7e7e7e7e;
> char   *valor[tam];
> int	canario2 = 0xe7e7e7e7;
> 
> Sin embargo, me lleve una sorpresa porque mostrando las posiciones de
> las variables en el stack, canario1 y canario2 aparecen junto con tam e
> i, pegadas al principio del stack, mientras que valor aparece mucho mas
> abajo!  Deduzco que el compilador se toma la libertad de reordenar las
> variables como le plazca.  Esto es asi tanto con -O0, como -O2 y sin
> especificar ninguna.

Como expliqué en mi correo en oss-devel, el arreglo automático no
reserva memoria de la misma manera que las variables locales normales,
esto tiene mucho sentido ya que si se pusieran en el orden que tu
esperabas, para acceder a "canario2" en tiempo de ejecución sería
necesario calcular su dirección cada vez.

El código que tu indicas es (casi) equivalente a:

 int canario1;
 char **valor;
 int canario2;
 valor = alloca( sizeof(tam) * sizeof(char *) );

La diferencia es que en mi ejemplo la dirección de memoria del arreglo
se guarda en una variable local con nombre, en el caso tuyo se crea una
variable local "invisible" con la dirección.

> > Para programas a nivel usuario el stack es inmenso de grande, asi que seria
> > muy muy raro que ocurriera eso.
> 
> Bueno, el programa de ejemplo se cae con SIGSEGV cuando el "tam" es
> mayor que algo de 1900000 (casi 2000000 realmente), lo cual por supuesto
> es esperable.  (Esto en x86-64 eso si).

El tamaño del stack _no_ es tan grande, debido a limitaciones de la
arquitectura. Básicamente, tienes que particionar la memoria en varias
áreas:

 * Código, creciendo hacia arriba.
 * Datos inicializados, idem.
 * Heap, creciedo hacia arriba.
 * Bibliotecas compartidas.
 * Stack, creciendo hacia abajo.

Para que el Stack y el Heap no se crucen con las biblitecas compartidas,
es necesario fijar una barrera en alguna parte. La mayoría de las
aplicaciones usan mucho más heap que stack, por lo que las bibliotecas
compartidas se colocan más cerca del límite del stack.

Esta barrera puede modificarse con el comando ulimit, si escribes:

 $ ulimit -s
 8192

En mi caso, se reservan 8192Kb para stack de las aplicaciones.

No es bueno reservar mucha memoria en el stack por varias razones:

* El stack es limitado, como ya se explicó. La práctica común es usar
  heap para bloques grandes de memoria.
* El stack guarda las variables locales, por lo que es muy importante
  que quede en el caché de la CPU. Manteniendo su uso bajo, se prioriza
  la localidad de datos y se mejora el rendimiento.
* As más fácil depurar problemas de manejo de memoria en el heap que en
  el stack, gracias a la existencia de guardas entre los bloques de
  memoria.

    Daniel.

PD: Buenos lugares para discutir estos temas son news://comp.lang.c y
news://comp.unix.programmer



Más información sobre la lista de distribución Linux