bds 2006 C 隐藏内存管理器冲突(类 new/delete[] 与 AnsiString) [英] bds 2006 C hidden memory manager conflicts (class new / delete[] vs. AnsiString)

查看:19
本文介绍了bds 2006 C 隐藏内存管理器冲突(类 new/delete[] 与 AnsiString)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 BDS 2006 Turbo C++ 很长时间了,我的一些大型项目(CAD/CAM、3D gfx 引擎和天文计算)偶尔会抛出例外(例如,3-12 个月 24/7 重载使用一次).经过大量调试后,我发现了这一点:

I am using BDS 2006 Turbo C++ for a long time now and some of my bigger projects (CAD/CAM,3D gfx engines and Astronomic computations) occasionally throw an exception (for example once in 3-12 months of 24/7 heavy duty usage). After extensive debugging I found this:

//code1:
struct _s { int i; }    // any struct
_s *s=new _s[1024];     // dynamic allocation
delete[] s;             // free up memory

这段代码通常在模板中,其中 _s 也可以是类,因此 delete[] 这段代码应该可以正常工作,但是 delete[]> 对结构不能正常工作(类看起来不错).没有异常被抛出,内存被释放,但它以某种方式破坏了内存管理器分配表,在此之后任何新分配都可能是错误的(新分配可能会与已分配的空间甚至未分配的空间创建重叠分配,因此偶尔会出现异常)

this code is usually inside template where _s can be also class therefore delete[] this code should work properly, but the delete[] does not work properly for structs (classes looks OK). No exceptions is thrown, the memory is freed, but it somehow damages the memory manager allocation tables and after this any new allocation can be wrong (new can create overlapped allocations with already allocated space or even unallocated space hence the occasional exceptions)

我发现如果我向 _s 添加空的析构函数,那么突然看起来一切正常

I have found that if I add empty destructor to _s than suddenly seems everything OK

struct _s { int i; ~_s(){}; }

现在是奇怪的部分.在我将其更新到我的项目后,我发现 AnsiString 类也有错误的重新分配.例如:

Well now comes the weird part. After I update this to my projects I have found that AnsiString class has also bad reallocations. For example:

//code2:
int i;
_s *dat=new _s[1024];
AnsiString txt="";
// setting of dat
for (i=0;i<1024;i++) txt+="bla bla bla
";
// usage of dat
delete[] dat;

在这段代码中,dat 包含一些有用的数据,然后是一些通过添加行创建的txt 字符串,因此必须重新分配一些txt有时 dat 数据被 txt 覆盖(即使它们没有重叠,我认为重新分配 所需的临时 AnsiStringtxtdat)

In this code dat contains some useful data, then later is some txt string created by adding lines so the txt must be reallocated few times and sometimes the dat data is overwritten by txt (even if they are not overlapped, I thing the temp AnsiString needed to reallocate txt is overlapped with dat)

所以我的问题是:

  1. 我在代码 1、代码 2 中做错了吗?
  2. 有什么办法可以避免AnsiString(重新)分配错误?(但仍在使用)

  1. Am I doing something wrong in code1, code2 ?
  2. Is there any way to avoid AnsiString (re)allocation errors ? (but still using it)

  • 经过大量调试(发布问题 2 后),我发现 AnsiString 不会引起问题.它们仅在使用它们时发生.真正的问题可能在于 OpenGL 客户端之间的切换.我有带有矢量图形预览的打开/保存对话框.如果我为这些 VCL 子窗口禁用 OpenGL 使用,那么 AnsiString 内存管理错误就会完全消失.我不知道是什么问题(MFC/VCL 窗口之间不兼容,或者更有可能我在切换上下文时犯了一些错误,将进一步调查).关注 OpenGL 窗口是:
  • main VCL Form + OpenGL Canvas 客户区
  • MFC 打开/保存对话框 + 停靠预览 VCL 表单 + OpenGLCanvas 客户区域内的子级
  • After extensive debugging (after posting question 2) I have found that AnsiString do not cause problems. They only occur while using them. The real problem is probably in switching between OpenGL clients. I have Open/Save dialogs with preview for vector graphics. If I disable OpenGL usage for these VCL sub-windows than AnsiString memory management errors disappears completely. I am not shore what is the problem (incompatibility between MFC/VCL windows or more likely I made some mistake in switching contexts, will further investigate). Concern OpenGL windows are:
  • main VCL Form + OpenGL inside Canvas client area
  • child of main MFC Open/Save dialog + docked preview VCL Form + OpenGL inside Canvas client area

附言

  1. 这些错误取决于new/delete/delete[] 的使用次数,而不是分配的大小
  2. code1 和 code2 的错误都是重复的(例如有一个解析器来加载复杂的 ini 文件,如果 ini 没有改变,错误发生在同一行)
  3. 我仅在结合使用 AnsiString 和具有内部动态分配的模板的大型项目(纯源代码 > 1MB)上检测到这些错误,但它们也可能在更简单的项目中出现我很少会想念它.
  4. 受感染的项目规格:
    • win32 noinstall standalone(使用 Win7sp1 x64,但在 XPsp3 x32 上表现相同)
    • 如果使用 GDIOpenGl/GLSL
    • 则不计量
    • 不计量是否使用设备驱动程序DLL
    • 没有OCX,或非标准的VCL组件
    • 没有 DirectX
    • 1 字节对齐编译/链接
    • 不要使用RTL、包或框架(独立)
  1. these errors depend on number of new/delete/delete[] usages not on the allocated sizes
  2. both code1 and code2 errors are repetitive (for example have a parser to load complex ini file and the error occurs on the same line if the ini is not changed)
  3. I detect these errors only on big projects (plain source code > 1MB) with combined usage of AnsiString and templates with internal dynamic allocations, but is possible that they are also in simpler projects but occurs so rarely that I miss it.
  4. Infected projects specs:
    • win32 noinstall standalone (using Win7sp1 x64 but on XPsp3 x32 behaves the same)
    • does not meter if use GDI or OpenGl/GLSL
    • does not meter if use device driver DLLs or not
    • no OCX,or nonstandard VCL component
    • no DirectX
    • 1 Byte aligned compilation/link
    • do not use RTL,packages or frameworks (standalone)

抱歉英语/语法不好...任何帮助/结论/建议表示赞赏.

Sorry for bad English/grammar ... any help / conclusion / suggestion appreciated.

推荐答案

经过大量调试后,我很好地隔离了问题.在您尝试为已删除的指针调用任何删除后,bds2006 Turbo C++ 的内存管理已损坏.例如:

After extensive debugging i finely isolated the problem. Memory management of bds2006 Turbo C++ became corrupt after you try to call any delete for already deleted pointer. for example:

BYTE *dat=new BYTE[10],*tmp=dat;
delete[] dat;
delete[] tmp;

此后内存管理不可靠.('new'可以分配已经分配的空间)

After this is memory management not reliable. ('new' can allocate already allocated space)

当然两次删除同一个指针是程序员方面的错误,但我已经找到了导致这个问题的所有问题的真正原因(源代码中没有任何明显的错误)请参阅此代码:

Of course deletion of the same pointer twice is bug on programmers side, but i have found the real cause of all my problems which generates this problem (without any obvious bug in source code) see this code:

//---------------------------------------------------------------------------
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();
    }
//---------------------------------------------------------------------------

在函数 get() 中被称为类 a 的析构函数两次.一次是真正的 a 一次是它的副本,因为我忘记创建构造函数

In function get() is called destructor for class a twice. Once for real a and once for its copy because I forget to create constructor

test::test(test &x);

[Edit1] 进一步升级代码

好的,我已经改进了类和结构甚至模板的初始化代码,以修复更多错误情况.将此代码添加到任何结构/类/模板,并在需要时添加功能

OK I have refined the initialization code for both class and struct even templates to fix even more bug-cases. Add this code to any struct/class/template and if needed than add functionality

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 是结构/类名
  • 仅当 T 在其中使用动态分配时才需要最后一个运算符,如果不使用分配,则可以保持原样
    • T is the struct/class name
    • the last operator is needed only if T uses dynamic allocations inside it if no allocations are used you can leave it as is
    • 这也解决了像这样的其他编译器问题:

      This also resolves other compiler issues like this:

      如果有人遇到类似的问题,希望这会有所帮助.

      If anyone have similar problems hope this helps.

      如果您需要调试您的代码,还可以查看 在 c++ 代码中回溯指针 mmap内存分配...

      Also look at traceback a pointer in c++ code mmap if you need to debug your memory allocations...

      这篇关于bds 2006 C 隐藏内存管理器冲突(类 new/delete[] 与 AnsiString)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆