memory management - bds 2006 C conflictos de administrador de memoria oculta(clase nueva/eliminar[] vs. AnsiString)
memory-management struct (1)
Estoy usando BDS 2006 Turbo C ++ durante mucho tiempo y algunos de mis proyectos más grandes ( CAD / CAM, motores gfx 3D y cálculos Astronomic) ocasionalmente lanzan una excepción (por ejemplo, una vez en 3-12 meses de uso intensivo las 24 horas, los 7 días de la semana) ) Después de una depuración exhaustiva, encontré esto:
//code1:
struct _s { int i; } // any struct
_s *s=new _s[1024]; // dynamic allocation
delete[] s; // free up memory
este código generalmente está dentro de la plantilla donde _s
también puede ser de clase, por lo tanto, delete[]
este código debería funcionar correctamente, pero la delete[]
no funciona correctamente para las estructuras (las clases se ven bien). No se lanzan excepciones, la memoria se libera, pero de alguna manera daña las tablas de asignación del administrador de memoria y después cualquier asignación nueva puede ser incorrecta (la nueva puede crear asignaciones superpuestas con espacio asignado o incluso espacio no asignado, por lo tanto, las excepciones ocasionales)
He encontrado que si agrego el destructor vacío a _s
de repente todo parece estar bien
struct _s { int i; ~_s(){}; }
Bueno, ahora viene la parte extraña. Después de actualizar esto a mis proyectos, he encontrado que la clase AnsiString
también tiene malas reasignaciones. Por ejemplo:
//code2:
int i;
_s *dat=new _s[1024];
AnsiString txt="";
// setting of dat
for (i=0;i<1024;i++) txt+="bla bla bla/r/n";
// usage of dat
delete[] dat;
En este código, dat
contiene algunos datos útiles, luego aparece una cadena de texto creada agregando líneas, por lo que el texto debe ser reasignado pocas veces y, a veces, los datos dat
son sobrescritos por txt
(incluso si no están superpuestos, creo que AnsiString
necesario tener AnsiString
para reasignar txt
se superpone con dat
)
Entonces mis preguntas son:
- ¿Estoy haciendo algo mal en code1, code2?
¿Hay alguna manera de evitar los
AnsiString
(re) allocation? (pero aún usándolo)- Después de una depuración exhaustiva (después de publicar la pregunta 2), he descubierto que
AnsiString
no causa problemas. Solo ocurren mientras los usan. El verdadero problema probablemente sea al cambiar de cliente OpenGL . Tengo diálogos de Abrir / Guardar con vista previa para gráficos vectoriales. Si desactivo el uso de OpenGL para estasAnsiString
deAnsiString
memoria deAnsiString
desaparece por completo. No estoy seguro de cuál es el problema (la incompatibilidad entre las ventanas de MFC / VCL o más bien cometí un error al cambiar de contexto, investigaré más a fondo). Las ventanas OpenGL con preocupación son: - Formulario principal de VCL + OpenGL dentro del área del cliente de
Canvas
- hijo del diálogo principal Abrir / Guardar de MFC + vista previa acoplada Formulario VCL + OpenGL dentro del área del cliente de
Canvas
- Después de una depuración exhaustiva (después de publicar la pregunta 2), he descubierto que
PD
- estos errores dependen del número de usos
new/delete/delete[]
no en los tamaños asignados - los errores de code1 y code2 son repetitivos (por ejemplo, tienen un analizador para cargar archivos ini complejos y el error ocurre en la misma línea si no se cambia la ini)
- Detecto estos errores solo en grandes proyectos (código fuente simple> 1MB) con el uso combinado de
AnsiString
y plantillas con asignaciones dinámicas internas, pero es posible que también estén en proyectos más simples, pero ocurre tan raramente que lo extraño. - Especificaciones de proyectos infectados:
- win32 noinstall independiente (con Win7sp1 x64 pero en XPsp3 x32 se comporta de la misma manera)
- no mide si usa GDI o OpenGl / GLSL
- no mide si usa DLL de controlador de dispositivo o no
- no OCX , o componente VCL no estándar
- sin DirectX
- Compilación / enlace alineado por 1 byte
- no use RTL , paquetes o marcos (independiente)
Perdón por mal inglés / gramática ... cualquier ayuda / conclusión / sugerencia apreciada.
Después de una depuración exhaustiva, finalmente aislé el problema. La administración de memoria de bds2006 Turbo C ++ se corrompió después de intentar llamar a cualquier eliminación del puntero ya eliminado. por ejemplo:
BYTE *dat=new BYTE[10],*tmp=dat;
delete[] dat;
delete[] tmp;
Después de esto, la administración de la memoria no es confiable. (''nuevo'' puede asignar espacio ya asignado)
Por supuesto, la eliminación del mismo puntero dos veces es un error en el lado de los programadores, pero he encontrado la verdadera causa de todos mis problemas que generan este problema (sin ningún error obvio en el código fuente) vea este código:
//---------------------------------------------------------------------------
class test
{
public:
int siz;
BYTE *dat;
test()
{
siz=10;
dat=new BYTE[siz];
}
~test()
{
delete[] dat; // <- add breakpoint here
siz=0;
dat=NULL;
}
test& operator = (const test& x)
{
int i;
for (i=0;i<siz;i++) if (i<x.siz) dat[i]=x.dat[i];
for ( ;i<siz;i++) dat[i]=0;
return *this;
}
};
//---------------------------------------------------------------------------
test get()
{
test a;
return a; // here call a.~test();
} // here second call a.~test();
//---------------------------------------------------------------------------
void main()
{
get();
}
//---------------------------------------------------------------------------
En la función get()
se llama destructor para la clase a dos veces. Una vez para real ay una para su copia porque se me olvida crear el constructor
test::test(test &x);
[Editar1] más actualizaciones del código
OK He refinado el código de inicialización para las plantillas even y struct even para arreglar aún más bug-cases. Agregue este código a cualquier estructura / clase / plantilla y, si es necesario, agregue la funcionalidad
T() {}
T(T& a) { *this=a; }
~T() {}
T* operator = (const T *a) { *this=*a; return this; }
//T* operator = (const T &a) { ...copy... return this; }
-
T
es el nombre de la estructura / clase - el último operador es necesario solo si
T
usa asignaciones dinámicas dentro de él si no se utilizan asignaciones, puede dejarlo como está
Esto también resuelve otros problemas del compilador como este:
- Demasiados errores de inicializadores para una matriz simple en bcc32
Si alguien tiene problemas similares, espero que esto ayude.
También mire en traceback un puntero en código c ++ mmap
si necesita depurar sus asignaciones de memoria ...