2010-12-06 17 views
6

Estoy tratando de producir una compilación especial de una aplicación monolítica grande. El problema que estoy tratando de resolver es rastrear grandes asignaciones de memoria difíciles de reproducir (30-80 gigabytes, a juzgar por lo que informa el sistema operativo). Creo que el problema es un std :: vector redimensionado a un valor entero negativo de 32 bits. La única plataforma que muestra este comportamiento es Solaris (tal vez sea la única plataforma que logra asignar con éxito tales fragmentos de memoria contigua). ¿Puedo reemplazar de forma global std :: vector con mi clase, delegando todas las llamadas al vector real, observando las asignaciones sospechosas (size > 0x7FFFFFFFu)? ¿Quizás reemplace selectivamente el constructor que toma size_t y los métodos resize()? Tal vez incluso secuestrar el operador global nuevo?Anulando operador global nuevo para rastrear grandes asignaciones de memoria?

+1

un valor de 32 bits no puede dar como resultado una IMO de 30-80 GigaByte, ¿quiere decir 64 bit –

+0

? Una matriz de 0xFFFFFFFF 8-byte estructuras toma ~ 34 gigabytes. –

+0

Estoy corregido –

Respuesta

5

¿Por qué no hacer algo como esto?

void *operator new(size_t size) 
{ 
    // if (size > MAX_SIZE) ... 
    return malloc(size); 
} 

void *operator new [](size_t size) 
{ 
    // if (size > MAX_SIZE) ... 
    return malloc(size); 
} 

Establecer un punto de interrupción en el if se encuentra el problema de inmediato.

+0

Sí, eso es lo que quiero lograr. Por supuesto, 'operator new' ya está definido en la biblioteca estándar de la plataforma, por lo que no puedo simplemente proporcionar una segunda implementación. –

+1

Sí, puedes. ¿Has probado? ¿Recibes errores de enlace? – detunized

+0

Sería genial si pudiera simplemente hacerlo así. Lo intentaré. –

2

Puede proporcionar un asignador personalizado en su vector en el momento de su construcción.

Puede simplemente delegar en std::allocator, y firewall el tamaño de la memoria solicitada, en la primera instancia.

+0

Mire, el problema es que no tengo idea qué parte del código se comporta mal. No es posible modificar la base de código completa (incluidas las bibliotecas de terceros) con asignadores personalizados en todos los lugares donde se usa un vector. –

+0

Sí, eso es más difícil entonces. El q lee como si ya supieras de qué vector se trata. ¿Su plataforma ofrece algún medio para atribuir bloques de pila creando callstack? –

+0

Puedo registrar la pila de llamadas cuando detecto una condición sospechosa. La pregunta es cómo detectarlo globalmente, sin cambiar cada clase usando un vector. –

0

Eche un vistazo a la implementación de la clase std::vector en la plataforma del problema. Cada implementación maneja la administración de la memoria de manera diferente (por ejemplo, aproximadamente el doble del espacio actualmente asignado cuando agrega un objeto fuera del tamaño de asignación actual del vector). Si sus objetos son lo suficientemente grandes y/o tiene una gran cantidad de entradas que se agregan al vector, sería posible intentar asignar más allá de la memoria disponible (contigua) en la computadora. Si ese es el caso, querrá buscar un asignador personalizado para ese vector.

Si está almacenando muchos elementos grandes en un vector, le recomendamos que consulte otra colección (por ejemplo, std::list) o intente guardar punteros en lugar de objetos reales.

+0

El problema que intento resolver no es cómo modificar el código para usar menos memoria.Estoy tratando de encontrar la pieza de código con errores que efectivamente hace 'vector.resize ((size_t) (- 1))'. Una vez que se identifica esa pieza, debe ser una tarea trivial para solucionarlo. –

+0

Si tiene acceso a un depurador que tiene la capacidad de punto de interrupción condicional, eso haría el truco. De lo contrario, intente cortar su colección a la mitad y pruebe para ver si se encuentra con el mismo problema. Aumente su colección en la mitad de los artículos restantes hasta que vea el problema. Mi reacción instintiva sería que, en algún punto del camino, el asignador de stock tiene la tarea de aumentar la capacidad de su colección duplicando su capacidad actual y se está quedando sin memoria contigua para asignar. –

+0

el código se ejecutará en el sitio del cliente en su entorno de control de calidad. Puedo acceder a los resultados de esa ejecución (archivos de registro), pero no puedo exigir que lo ejecuten en un depurador. –

0

Puede suministrar su propio tipo allocator a std::vector para realizar un seguimiento de la asignación. Pero dudo que ese sea el motivo. Primero, mirando los tamaños (30-80GB), concluyo que es un código de 64 bits. ¿Cómo podría el valor entero negativo de 32 bits llegar al tamaño del vector, que es de 64 bits, se habría promocionado a 64 bits primero para preservar el valor? Segundo, si este problema solo ocurre en Solaris, entonces puede indicar un problema diferente. Por lo que recuerdo, Solaris es el único sistema operativo que compromete la memoria en la asignación, los otros sistemas operativos solo marcan el espacio de direcciones asignado hasta que realmente se usen esas páginas de memoria. Entonces buscaría asignaciones no utilizadas.

+0

¿Cómo podría un valor negativo de 32 bits llegar a un tamaño de vector? Algo como esto: 'uint32_t count = (uint32_t) GetNumberOfThings(); std :: vector things (Thing(), count); 'cuando' GetNumberOfThings' devuelve -1 en error. Y sí, la base de código existente usa una gran cantidad de variables de 32 bits e incluso tiene una implementación de vector personalizado con un tamaño de 32 bits. El problema es rastrear la parte ofensiva del código ... –

Cuestiones relacionadas