Pregunta

Estoy usando MinGW con GCC 3.4.5 (mingw-special vista r3).

Mi aplicación C usa mucha pila, así que me preguntaba si hay alguna forma de saber mediante programación cuánta pila queda para poder manejar limpiamente la situación si descubro que estoy a punto de agotarse.

Si no, ¿qué otras formas solucionaría el problema de quedarse sin espacio en la pila?

No tengo idea de con qué tamaño de pila comenzaré, por lo que también necesitaría identificarlo mediante programación.

¿Fue útil?

Solución

Raymond Chen (Lo viejo y nuevo) tiene una buena respuesta a este tipo de preguntas:

Si tienes que preguntar, probablemente estés haciendo algo mal.

Aquí hay algunos detalles de Win32 sobre la asignación de pila: MSDN.

Si cree que podría estar limitado por el espacio de la pila, es casi seguro que estará limitado por la memoria virtual disponible, en cuyo caso necesitará encontrar una solución diferente.

¿Qué estás tratando de hacer exactamente?

Otros consejos

La función getrusage le proporciona el uso actual.(ver man getrusage).

El getrlimit en Linux ayudaría a obtener el tamaño de la pila con el RLIMIT_STACK parámetro.

#include <sys/resource.h>
int main (void)
{
  struct rlimit limit;

  getrlimit (RLIMIT_STACK, &limit);
  printf ("\nStack Limit = %ld and %ld max\n", limit.rlim_cur, limit.rlim_max);
}

Por favor echa un vistazo a man getrlimit.La misma información podría obtenerse mediante ulimit -s o ulimit -a fila de tamaño de pila.Échale un vistazo también a setrlimit función que permitiría establecer los límites.Pero como se mencionó en las otras respuestas, si necesita ajustar la pila, probablemente debería volver a considerar su diseño.Si desea una gran variedad, ¿por qué no tomar la memoria del montón?

Funcionaría sacar la dirección de una variable local de la pila.Luego en una llamada más anidada puedes restar la dirección de otro local para encontrar la diferencia entre ellos.

size_t top_of_stack;

void Main()
{
  int x=0;
  top_of_stack = (size_t) &x;

  do_something_very_recursive(....)
}

size_t SizeOfStack()
{
  int x=0;
  return top_of_stack - (size_t) &x;
} 

Si su código es de subprocesos múltiples, entonces debe ocuparse de almacenar la variable top_of_stack por subproceso.

compruebe si su compilador admite stackavail()

Suponiendo que conoce el tamaño de la pila completa, probablemente podría agregar algún código ensamblador para leer ESP.
Si lees ESP y lo guardas a un lado en la función principal, puedes comparar el ESP actual con el ESP que tienes en principal y ver cuánto ha cambiado el ESP.Eso le dará una indicación de cuánta pila está utilizando.

Éste es un problema al que he renunciado.Con mucho hackeo y (principalmente) oración, puedes obtener una solución que funcione en un momento dado en una máquina determinada.Pero, en general, no parece haber una manera decente de hacerlo.

Tendrá que obtener la posición y el tamaño de la pila desde fuera de su programa (en Linux puede obtenerlos desde /proc/<pid>/maps).En tu programa debes probar de alguna manera dónde estás en la pila.Es posible utilizar variables locales, pero no existe una garantía real de que realmente estén en la pila.También puede intentar obtener el valor del registro del puntero de la pila con algún ensamblado.

Ahora tienes la ubicación de la pila, su tamaño y la posición actual y asumes que sabes en qué dirección crece la pila.¿Cuándo entrarás en modo de desbordamiento de pila?Será mejor que no lo hagas cerca del final porque tu estimación (es decir,dirección de la variable local o valor del puntero de la pila) es probablemente demasiado optimista;No es raro direccionar la memoria más allá del puntero de la pila.Además, no tiene idea de cuánto espacio en la pila necesita una función determinada (y las funciones que llama).Así que tendrás que dejar bastante espacio al final.

Sólo puedo aconsejarte que no te metas en este lío y trates de evitar una recursividad muy profunda.Es posible que también desees aumentar el tamaño de tu pila;En Windows tienes que compilar esto en el ejecutable, creo.

Para ventanas:Hice esto antes de usar la función VirtualQuery de Kernel32.dll.Sólo tengo un ejemplo en C# pero demuestra la técnica:

public static class StackManagement
    {
        [StructLayout(LayoutKind.Sequential)]
        struct MEMORY_BASIC_INFORMATION
        {
            public UIntPtr BaseAddress;
            public UIntPtr AllocationBase;
            public uint AllocationProtect;
            public UIntPtr RegionSize;
            public uint State;
            public uint Protect;
            public uint Type;
        };

        private const long STACK_RESERVED_SPACE = 4096 * 16;

        public unsafe static bool CheckForSufficientStack(UInt64 bytes)
        {
            MEMORY_BASIC_INFORMATION stackInfo = new MEMORY_BASIC_INFORMATION();
            UIntPtr currentAddr = new UIntPtr(&stackInfo);
            VirtualQuery(currentAddr, ref stackInfo, sizeof(MEMORY_BASIC_INFORMATION));

            UInt64 stackBytesLeft = currentAddr.ToUInt64() - stackInfo.AllocationBase.ToUInt64();

            return stackBytesLeft > (bytes + STACK_RESERVED_SPACE);
        }

        [DllImport("kernel32.dll")]
        private static extern int VirtualQuery(UIntPtr lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
    }

POR CIERTO:Este código también se puede encontrar en StackOverflow en otra pregunta que hice cuando intentaba corregir un error en el código: La operación aritmética resultó en un desbordamiento en C# inseguroingrese la descripción del enlace aquí

tal vez esto ayude solo para la plataforma Windows:

en el encabezado PE (IMAGE_NT_HEADERS) de su exe hay algunos registros como:

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

typedef struct _IMAGE_OPTIONAL_HEADER {
    ...
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    ...
}

Existe una forma sencilla de obtener estos valores:usar GetModuleHandle(NULL) le dará la base de imágenes (identificador) de su módulo, dirección donde encontrará una estructura IMAGE_DOS_HEADER que le ayudará a encontrar la estructura IMAGE_NT_HEADERS (base de imágenes+IMAGE_DOS_HEADER.e_lfanew) -> IMAGE_NT_HEADERS, y ahí estará. Encontrarás esos campos: Tamaño de la reserva de pila y Compromiso de tamaño de pila.

La cantidad máxima de espacio que el sistema operativo asignará para su pila es SizeOfStackReserve.

Si consideras probar esto, házmelo saber y te ayudaré.Hay una manera de obtener el tamaño de pila utilizada en un punto determinado.

En Linux, llamaría a GetRusage y verificaría el miembro RU_ISRSS de Struct Rusage devuelto (tamaño integral de pila no compartida).

Desde el sitio MINGW y el seguimiento de parches del sitio sourceforge, veo que en mayo de 2008 se realizaron algunos parches en torno a getrusage y parece que ha sido compatible en general durante bastante tiempo.Debe verificar cuidadosamente si hay alguna advertencia en términos de qué parte de la funcionalidad típica de Linux es compatible con MinGW.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top