diff --git a/AecDbEwEquipment-analysis.md b/AecDbEwEquipment-analysis.md index 5eb0b17..1d74944 100644 --- a/AecDbEwEquipment-analysis.md +++ b/AecDbEwEquipment-analysis.md @@ -89,7 +89,7 @@ AecDbEwEquipment::~AecDbEwEquipment(void) // :1686 同类 `AecDbEwFitting` 的析构(`:584`)同样没处理它的子单元数组,属于同一批遗留写法。 -**修复**:析构里补 `FreeBuffer(m_arSubPrimPtrs);`(该函数已存在,见 2.3,需先修 2.3)。 +**修复**:析构里补 `FreeSubPrimData();`(成员函数,见 2.3 与 2.13)。 ### 2.3 P0:`FreeBuffer(CPtrArray&)` 只释放数据块,不释放结构体 @@ -109,7 +109,28 @@ void FreeBuffer(CPtrArray& arSubPrimPtrs) // :1520 被 `copyFrom:2181` 调用,于是 `copyFrom` 每次都泄漏被覆盖的那批 `XPrimData` 结构体。修 2.2 时会连带放大这个问题。 -另外这里无条件 `delete[](byte*)`,而 `releaseData()` 是按类型区分 `delete[]` / `delete` 的。`byJson`(`:820`)用 `new PVOID[]` 分配,属于数组,`delete[]` 恰好对;但若将来有类型用标量 `new`,这里就是堆损坏。**建议统一改成 `pData->releaseData(); DELETE_PTR(pData);`**,让释放规则只有一处。 +另外这里无条件 `delete[](byte*)`,而 `releaseData()` 是按类型区分 `delete[]` / `delete` 的。 + +**核查 `m_pData` 的全部分配点后,结论是 `releaseData()` 的类型判断不可靠**——同一个类型在内存里可能是对象,也可能是字节数组: + +| 来源 | 分配形式 | +| --- | --- | +| `dwgInFieldsForXPrim:206`(开图) | `new byte[n]`,所有类型 | +| `byJson:833`(JSON 导入) | `new PVOID[n]`,所有类型 | +| `copyXPrimData:150`(深拷贝) | `new byte[n]`,所有类型 | +| `CoreTools.cpp:2036` / `:4565` / `:4662` | `new byte[]` / `new char[]` | +| 各命令模块的 `setData`(8 处) | `kExtrude`/`kRevolve` 用 `new byte[]`,其余 `new T` | +| `PipelineCmd/command.cpp:18670` 等 5 处 | `new AecEqui::XNozz` / `new AecEqui::XBOX` | + +例如 `kBox` 从对话框创建时是 `new AecEqui::XBOX`,开图读回时却是 `new byte[]`。按 `m_eType` 判断,必然有一半场景不匹配(MSVC 下 POD 数组的 `delete` 与 `delete[]` 实际都走 `free`,所以一直没暴露)。 + +**改法:统一表示,再统一释放规则。** + +1. 把 13 处对象形式的分配改成 `new unsigned char[sizeof(T)]`(`sizeof(T)` 与原来一致,后续 `(T*)m_pData` 的用法不变) +2. `releaseData()` 去掉 switch,只保留 `delete[] (unsigned char*)m_pData` +3. `~XPrimData()` 改为先调 `releaseData()`,顺带修掉 `m_Combins` 子单元的 `m_pData` 泄漏 + +这样 `AecDbEwEquipment.cpp` 里的 `ReleaseXPrimData` 就不需要了,直接 `pData->releaseData(); DELETE_PTR(pData);`。 ### 2.4 P0:`subDMesh2NewSolid()` 删错元素,且泄漏 @@ -193,19 +214,56 @@ delete pEnt; // :4049 只删了 exp ### 2.12 内存问题汇总 -| 级别 | 问题 | 位置 | 触发频率 | 单次量级 | -| --- | --- | --- | --- | --- | -| P0 | 夹点数组重复分配 | `:1707` | 每个实体每次开图 | ~300 KB | -| P0 | 析构不释放几何单元 | `:1686` | 每个实体销毁 | 全部参数块 | -| P0 | `FreeBuffer` 不删结构体 | `:1520` | 每次 `copyFrom` | N 个结构体 | -| P0 | `subDMesh2NewSolid` 删错+泄漏 | `:3159` | 含 SubDMesh 的图 | N 个单元 + 几何错乱 | -| P1 | `RemoveSubPrimObj*` 漏 `releaseData` | `:4276` `:4291` | 编辑删除单元 | 1 个参数块 | -| P1 | `GetDraw2dables` 克隆泄漏 | `:2850` `:2857` | 2D 导出/剖切 | N 个 solid | -| P1 | 剖切克隆泄漏 | `:12691` `:12620` | 每次剖切 | N 个实体 | -| P1 | `readString` 未释放 | `:1720` | 每次开图 | 小 | -| P1 | `convertToRegion` 泄漏 | `:4032` | 最近点查询 | N 个 region | -| P2 | 空曲线丢弃 | `:11240` | 每次 2D 投影 | 小 | -| P2 | `ByJson` / `MakeBlockRefSet` 失败路径 | `:12853` `:12540` | 异常路径 | 小 | +| 级别 | 问题 | 位置 | 触发频率 | 单次量级 | 状态 | +| --- | --- | --- | --- | --- | --- | +| P0 | 夹点数组重复分配 | `:1707` | 每个实体每次开图 | ~300 KB | 已修 | +| P0 | 析构不释放几何单元 | `:1686` | 每个实体销毁 | 全部参数块 | 已修 | +| P0 | `FreeBuffer` 不删结构体 | `:1520` | 每次 `copyFrom` | N 个结构体 | 已修 | +| P0 | `subDMesh2NewSolid` 删错+泄漏 | `:3159` | 含 SubDMesh 的图 | N 个单元 + 几何错乱 | 已修 | +| P1 | `RemoveSubPrimObj*` 漏 `releaseData` | `:4276` `:4291` | 编辑删除单元 | 1 个参数块 | 已修 | +| P1 | `GetDraw2dables` 克隆泄漏 | `:2850` `:2857` | 2D 导出/剖切 | N 个 solid | 已修 | +| P1 | 剖切克隆泄漏 | `:12691` `:12620` | 每次剖切 | N 个实体 | 已修 | +| P1 | `readString` 未释放 | `:1720` | 每次开图 | 小 | 已修 | +| P1 | `convertToRegion` 泄漏 | `:4032` | 最近点查询 | N 个 region | 已修 | +| P1 | `GetDraw3dables` 合并后不删入参 | `:2975` | 每次导出 3D | N 个 solid | 已修 | +| P2 | 空曲线丢弃 | `:11240` | 每次 2D 投影 | 小 | 已修 | +| P2 | `ByJson` / `MakeBlockRefSet` 失败路径 | `:12853` `:12540` | 异常路径 | 小 | 已修 | + +“已修”的改动见 2.13。 + +### 2.13 第一批内存修复的实施记录 + +改动集中在 `CoreLibrary/AecDbEwEquipment.cpp`,不涉及头文件和存储格式。 + +| # | 实际改法 | 与原方案的差异 | +| --- | --- | --- | +| 1 | 删掉 `dwgInFields` 里的 `new AecGripData[GRIP_MAXNUM]`;`readString` 后补 `acutDelString(pszTmp)` | 同原方案 | +| 2 | 析构补 `FreeSubPrimData()` | 同原方案 | +| 3 | `FreeSubPrimData()` 成员函数:逐个 `releaseData()` + `DELETE_PTR`,最后 `RemoveAll` | 见 2.3,先统一了 `m_pData` 表示 | +| 4 | `subDMesh2NewSolid()` 按 `idxs` 倒序释放 + `RemoveAt` | 同原方案,另把 `size_t i` 改成 `int i` 倒序 | +| 5 | `RemoveSubPrimObj` / `RemoveSubPrimObjByID` 改用 `releaseData()` + `DELETE_PTR` | 同原方案 | +| 6 | `GetDraw2dables` 两个 `continue` 前补 `DELETE_PTR(pClnEnt)` | 同原方案 | +| 7 | `OldGetSectionDraw` 循环内补 `DELETE_PTR(pSubCln)`、循环后补 `FreeEntityArray(arSubPtrs)`;`GetSectionDraw` 两处 `return OldGetSectionDraw` 前补 `delete pFit` | 同原方案 | +| 8 | `convertToRegion` 的 `regions` 循环结束后逐个 `DELETE_PTR`;顺带把内层遮蔽的 `i` 改为 `j` | 同原方案 | +| 9 | `SortAecComplexCurves` 空曲线改为 `DELETE_PTR` | 同原方案,另补 `pCrv == NULL` 判断 | +| 10 | `ByJson` 循环前 `FreeSubPrimData()`,`byJson` 失败时 `releaseData()` + `DELETE_PTR` | 同原方案 | +| 11 | `MakeBlockRefSet` 的 `getBlockTable` / `pTbl->add` 失败时 `pRec->close()` 并返回 `false` | 同原方案 | +| 12 | `dwgInFields` 的 `m_arSubPrimPtrs.RemoveAll()` 改为 `FreeSubPrimData()` | 新增,原注释写着 FreeBufer 但没真释放 | +| 13 | `GetDraw3dables` 的 `booleanOper(kBoolUnite)` 之后补 `DELETE_PTR(pSolid)` | 新增,见 3.15 | + +**函数命名整理**(`AecDbEwEquipment.cpp` 原来有 4 个文件作用域、外部链接的 `FreeBuffer*`,与其他 cpp 里的同名 `static` 函数容易混淆): + +| 原名 | 现名 | 说明 | +| --- | --- | --- | +| `FreeBuffer(CPtrArray&)` | `AecDbEwEquipment::FreeSubPrimData()` | 只处理 `m_arSubPrimPtrs`,改成成员函数后参数不再需要 | +| `FreeBuffer(AcDbVoidPtrArray&)` | `static FreeEntityArray()` | 通用实体数组,加 `static` 收回内部链接 | +| `FreeBuffer2(CPtrArray&)` | `static FreeComplexCurveArray()` | `AecComplexCurve` 数组 | +| `FreeBuffer3(CPtrArray&)` | `static FreeFaceplanArray()` | `Aec3dFaceplan` 数组 | + +**尚未处理**: + +- 2.8 的第二个问题(为了算最近点把临时 solid 写进模型空间再 erase),属于副作用与性能,放在第三批 + --- @@ -365,11 +423,16 @@ for (...) { | 位置 | 写法 | 若 SDK 会删除入参 | 若 SDK 不删除入参 | | --- | --- | --- | --- | -| `:3774` | `booleanOper(...); DELETE_PTR(p);` | 二次释放 | 正确 | -| `:3867` `:3964` | `booleanOper(...)` 后统一 `deleteArrayVoidPtrs` | 二次释放 | 正确 | -| `:2964` | `booleanOper(kBoolUnite, pSolid)`,克隆体不再处理 | 正确 | 每次泄漏一个克隆 | +| `:3790` | `booleanOper(...); DELETE_PTR(p);` | 二次释放 | 正确 | +| `:3883` `:3980` | `booleanOper(...)` 后统一 `deleteArrayVoidPtrs` | 二次释放 | 正确 | +| `:14198` | `booleanOper(...); DELETE_PTR(pSolid);` | 二次释放 | 正确 | +| `:2975` | `booleanOper(kBoolUnite, pSolid)`,克隆体不再处理 | 正确 | 每次泄漏一个克隆 | -也就是说:**无论 SDK 语义是哪一种,这三处至少有一处是错的**。需要先用最小样例(两个 box 做 unite,然后只删第二个)在调试版 + Application Verifier 下确认,再统一写法。这条不确认,2.6 和 2.7 的修复方式都不好定。 +本文件 5 处调用里 4 处都主动释放入参,`:2975` 是唯一的例外。 + +**2026-10-23 结论**:按「`booleanOper` 不删除入参」处理,`:2975` 补 `DELETE_PTR(pSolid)`(见 2.13 #13)。依据是同一文件另外 4 处(含失败路径 `:2002` 的 `DELETE_PTR(pSolidInside)`)都按调用方负责释放来写;若 SDK 实际会删除入参,这些既有代码早就在正常流程里二次释放崩掉了。 + +另外 `CoreLibrary/AcDbX3dSolid.cpp:1998` 的 `booleanOper` 成功路径没有释放 `pSolidInside`,同一约定下也是一个泄漏点,不在本次范围。 ### 3.16 其他 @@ -468,21 +531,23 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里 ### 5.1 第一批:内存与正确性(不改接口、不改格式) -| # | 改动 | 位置 | 风险 | -| --- | --- | --- | --- | -| 1 | 删掉 `dwgInFields` 里的重复分配,`readString` 补 `acutDelString` | `:1707` `:1720` | 低 | -| 2 | 析构补 `FreeBuffer(m_arSubPrimPtrs)` | `:1686` | 低(依赖 #3) | -| 3 | `FreeBuffer(CPtrArray&)` 改为 `releaseData()` + `DELETE_PTR` | `:1520` | 低 | -| 4 | `subDMesh2NewSolid` 按下标倒序删除并释放 | `:3159` | 中(涉及几何正确性,需样例图) | -| 5 | `RemoveSubPrimObj*` 补 `releaseData()` | `:4276` `:4291` | 低 | -| 6 | `subErase` 的 `Find` 补 `!= -1` | `:2119` | 低(行为会变,需回归删除阀门) | -| 7 | `DrawHandFlg` 的 `==` 改 `=` | `:2656` | 低 | -| 8 | `ProcessHlrResult` 改用 `it = erase(it)` | `:13128` | 低 | -| 9 | `copyFrom` 补 `m_bVert` / `m_idDash` / `m_idCenter` | `:2174` | 低 | -| 10 | `GetSectionDraw` 返回值改 `nCoundPre - nCount` | `:12762` | 低(需确认调用方语义) | -| 11 | `clearGeoBuffer` 实现为清 2D/3D 缓存 | `:12861` | 低 | +拆成两批提交:**内存问题已做(见 2.13)**,逻辑缺陷待做。 -这一批做完,开图内存和几个明确的逻辑错误就都清掉了,且不触碰存储格式。 +| # | 改动 | 位置 | 风险 | 状态 | +| --- | --- | --- | --- | --- | +| 1 | 删掉 `dwgInFields` 里的重复分配,`readString` 补 `acutDelString` | `:1707` `:1720` | 低 | 已完成 | +| 2 | 析构补 `FreeSubPrimData()` | `:1686` | 低(依赖 #3) | 已完成 | +| 3 | `releaseData()` 统一 `delete[]`,`FreeSubPrimData()` 释放 `m_pData` 后删结构体 | `:1520` | 低 | 已完成(见 2.3、2.13) | +| 4 | `subDMesh2NewSolid` 按下标倒序删除并释放 | `:3159` | 中(涉及几何正确性,需样例图) | 已完成 | +| 5 | `RemoveSubPrimObj*` 补释放 `m_pData` | `:4276` `:4291` | 低 | 已完成 | +| 6 | `subErase` 的 `Find` 补 `!= -1` | `:2119` | 低(行为会变,需回归删除阀门) | 待做 | +| 7 | `DrawHandFlg` 的 `==` 改 `=` | `:2656` | 低 | 待做 | +| 8 | `ProcessHlrResult` 改用 `it = erase(it)` | `:13128` | 低 | 待做 | +| 9 | `copyFrom` 补 `m_bVert` / `m_idDash` / `m_idCenter` | `:2174` | 低 | 待做 | +| 10 | `GetSectionDraw` 返回值改 `nCoundPre - nCount` | `:12762` | 低(需确认调用方语义) | 待做 | +| 11 | `clearGeoBuffer` 实现为清 2D/3D 缓存 | `:12861` | 低 | 待做 | + +另外补做的 4 处内存修复(2.6、2.7、2.9、2.10、2.11、`GetDraw3dables` 合并泄漏、`dwgInFields` 的 `RemoveAll`)见 2.13。 ### 5.2 第二批:`m_Combins` 存盘清空(需要确认影响面) @@ -507,7 +572,7 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里 ### 5.4 需要先确认的事 -1. `booleanOper` 是否删除入参(3.15)—— 决定 2.6 / 2.7 怎么修 +1. ~~`booleanOper` 是否删除入参(3.15)~~ —— 2026-10-23 按「不删除入参」处理,理由见 3.15 2. `GetSectionDraw` 的返回值调用方到底期望什么(3.5) 3. `PreprocessForHlr` 的 `mat4` 双次变换是否刻意(3.12) 4. `kCombination` 单元的实际存量(5.2) @@ -519,7 +584,8 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里 | 改动 | 验证方式 | | --- | --- | | 夹点数组 / 析构释放 | 打开含 1000+ 设备的图纸,任务管理器看私有字节;关图后应回落 | -| `FreeBuffer` 改 `releaseData` | 各类单元(box/cylinder/cone/Revit/组合)各删一个,确认无崩溃 | +| `releaseData` 统一 `delete[]` | 各类单元(box/cylinder/cone/Revit/组合)各删一个,确认无崩溃;开图→改参数→存盘→重开,几何完整 | +| 剖切 / 2D 导出 | 对含阀门、法兰、普通设备的图各剖一次,反复开关剖切对话框,内存不持续上涨 | | `subDMesh2NewSolid` | 含 SubDMesh 的样例图,开图后单元数量与类型正确,绘制不缺体 | | `subErase` | 删除阀门/接头/普通设备各一次,确认只有阀门走合并管线 | | `HLR_CALC` | 剖切过程中保存再重开,设备 3D 仍可见 | @@ -541,8 +607,8 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里 ## 8. 实施顺序 -1. 第一批 1~5(内存),单独一个 PR,可独立验证 +1. ~~第一批 1~5(内存),单独一个 PR,可独立验证~~ —— 已完成,范围扩到 2.1~2.11 全部内存项,见 2.13 2. 第一批 6~11(逻辑),单独一个 PR -3. 确认 5.4 的四个问题 +3. 确认 5.4 剩下的三个问题 4. 第二批(`m_Combins`),视存量决定是否做 5. 第三批按 4.7 度量结果排序,一项一个 PR diff --git a/SourceCode/Code2026/CoreLibrary/AecDbEwEquipment.cpp b/SourceCode/Code2026/CoreLibrary/AecDbEwEquipment.cpp index 8e40d66..ad15060 100644 --- a/SourceCode/Code2026/CoreLibrary/AecDbEwEquipment.cpp +++ b/SourceCode/Code2026/CoreLibrary/AecDbEwEquipment.cpp @@ -871,7 +871,7 @@ namespace } #pragma region - void FreeBuffer2(CPtrArray& arCplptrs) + static void FreeComplexCurveArray(CPtrArray& arCplptrs) { for (int i = 0; i < arCplptrs.GetSize(); i++) { @@ -884,7 +884,7 @@ namespace arCplptrs.RemoveAll(); } - void FreeBuffer3(CPtrArray& arCplptrs) + static void FreeFaceplanArray(CPtrArray& arCplptrs) { for (int i = 0; i < arCplptrs.GetSize(); i++) { @@ -1506,7 +1506,7 @@ namespace return bOk; } - void FreeBuffer(AcDbVoidPtrArray& arEntPtrs) + static void FreeEntityArray(AcDbVoidPtrArray& arEntPtrs) { AcDbEntity* pEnt = NULL; while (arEntPtrs.length() > 0) @@ -1517,22 +1517,6 @@ namespace } } - void FreeBuffer(CPtrArray& arSubPrimPtrs) - { - for (int i = 0; i < arSubPrimPtrs.GetSize(); i++) - { - AecEqui::XPrimData* pData = (AecEqui::XPrimData*)arSubPrimPtrs.GetAt(i); - if (pData != NULL) - { - if (pData->m_nSize > 0) - { - delete[](byte*)pData->m_pData; - } - } - } - arSubPrimPtrs.RemoveAll(); - } - void TransformEntity(AcDbEntity *p , const AcGePoint3d &ptIns , const AcGeVector3d &vtDir @@ -1687,6 +1671,7 @@ AecDbEwEquipment::~AecDbEwEquipment(void) { Clean3DBuffer(); Clean2DBuffer(); + FreeSubPrimData(); delete [] m_pGripAppData; } @@ -1704,7 +1689,7 @@ Acad::ErrorStatus AecDbEwEquipment::dwgInFields(AcDbDwgFiler* pFiler) } //----- Object version number needs to be read first - m_pGripAppData = new AecGripData[GRIP_MAXNUM]; + //夹点数组由构造函数分配,此处不要再分配一次,否则旧数组直接泄漏(约 300KB/实体) Adesk::UInt32 version = 0; if ((es = pFiler->readUInt32(&version)) != Acad::eOk) return (es); @@ -1721,6 +1706,7 @@ Acad::ErrorStatus AecDbEwEquipment::dwgInFields(AcDbDwgFiler* pFiler) if (pszTmp != NULL) { m_sGUID = pszTmp; + acutDelString(pszTmp); } ////////////////////////////////////////////////////////////////////////// @@ -1728,8 +1714,8 @@ Acad::ErrorStatus AecDbEwEquipment::dwgInFields(AcDbDwgFiler* pFiler) Adesk::Int32 nLen = 0; pFiler->readInt32(&nLen); - //FreeBufer - m_arSubPrimPtrs.RemoveAll(); + //重新读入前先释放旧几何,只 RemoveAll 会漏掉结构体和参数块 + FreeSubPrimData(); AecEqui::XPrimData* pSolid = NULL; Adesk::Int16 nType = 0; @@ -2177,9 +2163,8 @@ Acad::ErrorStatus AecDbEwEquipment::copyFrom(const AcRxObject* pSrc) AecDbEntityBase::copyFrom(pSrc); - //FreeBufer!!!! - FreeBuffer(m_arSubPrimPtrs); - m_arSubPrimPtrs.RemoveAll(); + //先释放旧几何,否则被覆盖的那批结构体和参数块全部泄漏 + FreeSubPrimData(); AecDbEwEquipment* pImp = (AecDbEwEquipment*)pSrc; if (pImp != NULL) @@ -2848,6 +2833,7 @@ int AecDbEwEquipment::GetDraw2dables(Adesk::UInt16 nDrawStyle, AcDbVoidPtrArray& { //投影法 OrthoProjected3DSolid(pSolid,plan,xform,arSubEntPtrs); + DELETE_PTR(pClnEnt); //投影函数不接管所有权,原来直接 continue 导致克隆体泄漏 continue; } @@ -2855,6 +2841,7 @@ int AecDbEwEquipment::GetDraw2dables(Adesk::UInt16 nDrawStyle, AcDbVoidPtrArray& if (pSubMesh != NULL) { OrthoProjected3DSubMesh(pSubMesh,plan,xform,arSubEntPtrs); + DELETE_PTR(pClnEnt); continue; } @@ -2962,6 +2949,8 @@ int AecDbEwEquipment::GetDraw3dables(AcDbVoidPtrArray& arEntPtrs,bool bWriteBimI else { pSolidAll->booleanOper(AcDb::kBoolUnite,pSolid); + //booleanOper 不接管入参,原来每个被合并掉的克隆体都泄漏 + DELETE_PTR(pSolid); } } else @@ -3156,9 +3145,17 @@ void AecDbEwEquipment::subDMesh2NewSolid() } } - for (size_t i(0); i < idxs.size(); ++i) + //必须倒序删除:idxs 里存的是删除前的原始下标,正序删会让后面的下标整体前移 + for (int i((int)idxs.size() - 1); i >= 0; --i) { - m_arSubPrimPtrs.RemoveAt(i); + int nIndex = idxs[i]; + AecEqui::XPrimData *p = (AecEqui::XPrimData *)m_arSubPrimPtrs[nIndex]; + if (p != NULL) + { + p->releaseData(); + DELETE_PTR(p); + } + m_arSubPrimPtrs.RemoveAt(nIndex); } m_arSubPrimPtrs.Append(ar); @@ -4031,9 +4028,9 @@ bool AecDbEwEquipment::GetClosestPointToSUbPrim(DWORD dwSubiD, AcGePoint3d& ptNe AcArray regions; pFace->convertToRegion(regions); - for (int i = 0; i < regions.length(); i++) + for (int j = 0; j < regions.length(); j++) { - AcDbRegion *pIn = (AcDbRegion *)regions.at(i); + AcDbRegion *pIn = (AcDbRegion *)regions.at(j); CoreTools::getRegionInfo(pIn, ptC, dA, pln); @@ -4045,6 +4042,10 @@ bool AecDbEwEquipment::GetClosestPointToSUbPrim(DWORD dwSubiD, AcGePoint3d& ptNe mpPns.insert(std::make_pair(pn.dDis, pn)); } + + //convertToRegion 产出的 region 归调用方所有,原来一个都没释放 + for (int j = 0; j < regions.length(); j++) + DELETE_PTR(regions[j]); } delete pEnt; } @@ -4264,6 +4265,20 @@ void AecDbEwEquipment::AddSubPrimObj(AecEqui::XPrimData* p) m_arSubPrimPtrs.Add(pData); } +void AecDbEwEquipment::FreeSubPrimData() +{ + for (int i = 0; i < m_arSubPrimPtrs.GetSize(); i++) + { + AecEqui::XPrimData* pData = (AecEqui::XPrimData*)m_arSubPrimPtrs.GetAt(i); + if (pData != NULL) + { + pData->releaseData(); + DELETE_PTR(pData); + } + } + m_arSubPrimPtrs.RemoveAll(); +} + void AecDbEwEquipment::RemoveSubPrimObj(int nIndex) { AssertWriteEnabled(); @@ -4273,6 +4288,7 @@ void AecDbEwEquipment::RemoveSubPrimObj(int nIndex) pSolid = (AecEqui::XPrimData*)m_arSubPrimPtrs.GetAt(nIndex); m_arSubPrimPtrs.RemoveAt(nIndex); m_mapSpecXData.RemoveAt(TypeConvert::i2s(pSolid->m_nID) + _T(":color")); + pSolid->releaseData(); DELETE_PTR(pSolid); } } @@ -4288,6 +4304,7 @@ void AecDbEwEquipment::RemoveSubPrimObjByID(int nSubID) { m_arSubPrimPtrs.RemoveAt(i); m_mapSpecXData.RemoveAt(TypeConvert::i2s(pSolid->m_nID) + _T(":color")); + pSolid->releaseData(); DELETE_PTR(pSolid); break; } @@ -8517,8 +8534,8 @@ void AecDbEwEquipment::PrimPorjectToPlan(AecComplexCurve& cplCurve, AecEqui::XVi } //3.释放内存 - FreeBuffer2(arPrimCplPtrs); - FreeBuffer3(arFaceplanPtrs); + FreeComplexCurveArray(arPrimCplPtrs); + FreeFaceplanArray(arFaceplanPtrs); } void AecDbEwEquipment::PrimBoxPorjectToPlan(AecComplexCurve& cplCurve, AecEqui::XView eview, const AcGeVector3d& vtNor, AecEqui::XPrimData* p3dSolid, Aec3dFaceplan* pPlan, BOOL bMakeCenterLine /*= FALSE*/, BOOL bOnlyGetFace /*= FALSE*/) const @@ -11233,7 +11250,11 @@ void AecDbEwEquipment::SortAecComplexCurves(CPtrArray& arPrimCplPtrs) const for (int i = 0; i < arPrimCplPtrs.GetSize(); i++) { AecComplexCurve* pCrv = (AecComplexCurve*)arPrimCplPtrs.GetAt(i); - if (pCrv->length() > 0) vtComplexcrv.push_back(pCrv); + if (pCrv == NULL) continue; + if (pCrv->length() > 0) + vtComplexcrv.push_back(pCrv); + else + DELETE_PTR(pCrv); //空曲线原来被直接丢弃,泄漏 } std::sort(vtComplexcrv.begin(), vtComplexcrv.end(), CompareComplexcrvByZ); @@ -11337,7 +11358,7 @@ void AecDbEwEquipment::SplitCrvOnIntersect(AecComplexCurve* pCrvDn, AecComplexCu AecCoverBooleanOper::SortPoints(arPts, pDbCrvDn); pDbCrvDn->getSplitCurves(arPts, arSegPtrs); AppendSegment(elDn, cplexDn, arSegPtrs, dZ); - FreeBuffer(arSegPtrs); + FreeEntityArray(arSegPtrs); } else { @@ -11351,7 +11372,7 @@ void AecDbEwEquipment::SplitCrvOnIntersect(AecComplexCurve* pCrvDn, AecComplexCu *pCrvDn = cplexDn; - FreeBuffer(arUpCrvPtrs); + FreeEntityArray(arUpCrvPtrs); } AcDbCurve* AecDbEwEquipment::CurveElement2DbCurve(AecEqui::AecCurveElement el) const @@ -12556,35 +12577,44 @@ DLLIMPEXP bool MakeBlockRefSet(AcDbVoidPtrArray& arEntPtrs,const AcDbObjectId& i AcDbObjectId idRec; AcDbBlockTable *pTbl = NULL; - if (Acad::eOk == pDb->getBlockTable(pTbl, AcDb::kForWrite)) + if (Acad::eOk != pDb->getBlockTable(pTbl, AcDb::kForWrite) || pTbl == NULL) { - pTbl->add(idRec, pRec); - pTbl->close(); - - TCHAR szHd[17]; - idRec.handle().getIntoAsciiBuffer(szHd); - - if (_tcscmp(pszName, _T("*U")) == 0 || - _tcscmp(pszName, _T("*u")) == 0) - { - } - else - { - sName.Format(_T("%s@%s"), pszName, szHd); - Acad::ErrorStatus es = pRec->setName(sName); - } - + //原来这里直接跳过,pRec 既不关闭也不删除,每次调用泄漏一个块表记录 pRec->close(); + return false; + } - if (idRec.isValid()) - { - AcDbBlockReference *pRef = new AcDbBlockReference; - pRef->setBlockTableRecord(idRec); - pRef->setRotation(0); - pRef->setPosition(ptIns); - pRef->setLayer(idLay); - arEntPtrs.append(pRef); - } + Acad::ErrorStatus esAdd = pTbl->add(idRec, pRec); + pTbl->close(); + if (esAdd != Acad::eOk) + { + pRec->close(); + return false; + } + + TCHAR szHd[17]; + idRec.handle().getIntoAsciiBuffer(szHd); + + if (_tcscmp(pszName, _T("*U")) == 0 || + _tcscmp(pszName, _T("*u")) == 0) + { + } + else + { + sName.Format(_T("%s@%s"), pszName, szHd); + Acad::ErrorStatus es = pRec->setName(sName); + } + + pRec->close(); + + if (idRec.isValid()) + { + AcDbBlockReference *pRef = new AcDbBlockReference; + pRef->setBlockTableRecord(idRec); + pRef->setRotation(0); + pRef->setPosition(ptIns); + pRef->setLayer(idLay); + arEntPtrs.append(pRef); } return true; } @@ -12624,8 +12654,12 @@ bool AecDbEwEquipment::OldGetSectionDraw(AcGePlane &plan, const AcGeVector3d &vt { OrthoProjected3DSolid(pSolidT, plan, xform, arProPtrs); } + //非 solid 的克隆体原来既不进结果也不释放 + DELETE_PTR(pSubCln); } } + //GetDraw3dables 产出的整组克隆,原来从头到尾没释放 + FreeEntityArray(arSubPtrs); CString sName; m_mapSpecXData.GetAt(KEY_NAME, sName); @@ -12688,6 +12722,7 @@ bool AecDbEwEquipment::GetSectionDraw(AcGePlane& plan,const AcGeVector3d& vtTo,A //不是2个接口,走投影,不画符号 if (pFit->GetInterfaceCount() != 2) { + delete pFit; //原来直接 return,克隆出来的整份设备泄漏 return OldGetSectionDraw(plan, vtTo, arRegionPtrs); } @@ -12739,6 +12774,7 @@ bool AecDbEwEquipment::GetSectionDraw(AcGePlane& plan,const AcGeVector3d& vtTo,A } else//不是阀门,其他设备 { + delete pFit; return OldGetSectionDraw(plan, vtTo, arRegionPtrs); } } @@ -12848,11 +12884,21 @@ bool AecDbEwEquipment::ByJson(const SHJson::WValue &v) it = v.FindMember(_T("__arSubPrimPtrs__")); if (it == v.MemberEnd()) return false; if (!it->value.IsArray()) return false; + + //先释放旧几何,否则对已有对象再导入会叠加重复单元 + FreeSubPrimData(); + for (VCIt i = it->value.Begin(); i != it->value.End(); ++i) { AecEqui::XPrimData *p = new AecEqui::XPrimData; if (byJson(*i, p)) m_arSubPrimPtrs.Add(p); + else + { + //解析失败,原来既不进数组也不释放 + p->releaseData(); + DELETE_PTR(p); + } } return true; diff --git a/SourceCode/Code2026/ElecCmd/BDQGDlg.cpp b/SourceCode/Code2026/ElecCmd/BDQGDlg.cpp index c809366..ac52200 100644 --- a/SourceCode/Code2026/ElecCmd/BDQGDlg.cpp +++ b/SourceCode/Code2026/ElecCmd/BDQGDlg.cpp @@ -57,7 +57,7 @@ namespace { ::Sleep(30); pXPData->m_nID = ::GetTickCount(); - pXPData->m_pData = new T; + pXPData->m_pData = new unsigned char[sizeof(T)]; ::memcpy(pXPData->m_pData, pData, sizeof(T)); pXPData->m_nSize = sizeof(T); } diff --git a/SourceCode/Code2026/ElecCmd/ElecCmdCommand.cpp b/SourceCode/Code2026/ElecCmd/ElecCmdCommand.cpp index 69acbc9..23e4bd5 100644 --- a/SourceCode/Code2026/ElecCmd/ElecCmdCommand.cpp +++ b/SourceCode/Code2026/ElecCmd/ElecCmdCommand.cpp @@ -6131,7 +6131,7 @@ namespace } break; default: - pXPData->m_pData = new T; + pXPData->m_pData = new unsigned char[sizeof(T)]; ::memcpy(pXPData->m_pData, pData, sizeof(T)); pXPData->m_nSize = sizeof(T); break; diff --git a/SourceCode/Code2026/PipelineCmd/EquipmentMakeDlg.cpp b/SourceCode/Code2026/PipelineCmd/EquipmentMakeDlg.cpp index 01b5e5e..055a6da 100644 --- a/SourceCode/Code2026/PipelineCmd/EquipmentMakeDlg.cpp +++ b/SourceCode/Code2026/PipelineCmd/EquipmentMakeDlg.cpp @@ -321,7 +321,7 @@ namespace } break; default: - pXPData->m_pData = new T; + pXPData->m_pData = new unsigned char[sizeof(T)]; ::memcpy(pXPData->m_pData, pData, sizeof(T)); pXPData->m_nSize = sizeof(T); break; diff --git a/SourceCode/Code2026/PipelineCmd/YMJCDlg.cpp b/SourceCode/Code2026/PipelineCmd/YMJCDlg.cpp index 88135be..176380f 100644 --- a/SourceCode/Code2026/PipelineCmd/YMJCDlg.cpp +++ b/SourceCode/Code2026/PipelineCmd/YMJCDlg.cpp @@ -275,7 +275,7 @@ namespace } break; default: - pXPData->m_pData = new T; + pXPData->m_pData = new unsigned char[sizeof(T)]; ::memcpy(pXPData->m_pData, pData, sizeof(T)); pXPData->m_nSize = sizeof(T); break; diff --git a/SourceCode/Code2026/PipelineCmd/command.cpp b/SourceCode/Code2026/PipelineCmd/command.cpp index b858087..1fd98a7 100644 --- a/SourceCode/Code2026/PipelineCmd/command.cpp +++ b/SourceCode/Code2026/PipelineCmd/command.cpp @@ -18667,7 +18667,7 @@ void PL_PARAM_NOZZ() data.m_nID = ::_time32(NULL); data.m_iClr = 1; - data.m_pData = new AecEqui::XNozz; + data.m_pData = new unsigned char[sizeof(AecEqui::XNozz)]; ::memcpy(data.m_pData, pNozzData, sizeof(AecEqui::XNozz)); data.m_nSize = sizeof(AecEqui::XNozz); data.m_nActiveInf = 0; diff --git a/SourceCode/Code2026/PlumbingCmd/CSXHDlg.cpp b/SourceCode/Code2026/PlumbingCmd/CSXHDlg.cpp index a18dd5d..a5aaa3f 100644 --- a/SourceCode/Code2026/PlumbingCmd/CSXHDlg.cpp +++ b/SourceCode/Code2026/PlumbingCmd/CSXHDlg.cpp @@ -27,7 +27,7 @@ namespace } break; default: - pXPData->m_pData = new T; + pXPData->m_pData = new unsigned char[sizeof(T)]; ::memcpy(pXPData->m_pData, pData, sizeof(T)); pXPData->m_nSize = sizeof(T); break; diff --git a/SourceCode/Code2026/PlumbingCmd/command.cpp b/SourceCode/Code2026/PlumbingCmd/command.cpp index 646fbc7..2186a85 100644 --- a/SourceCode/Code2026/PlumbingCmd/command.cpp +++ b/SourceCode/Code2026/PlumbingCmd/command.cpp @@ -50,7 +50,7 @@ namespace } break; default: - pXPData->m_pData = new T; + pXPData->m_pData = new unsigned char[sizeof(T)]; ::memcpy(pXPData->m_pData, pData, sizeof(T)); pXPData->m_nSize = sizeof(T); break; diff --git a/SourceCode/Code2026/Pool3dCmd/SBZWDlg.cpp b/SourceCode/Code2026/Pool3dCmd/SBZWDlg.cpp index cceccd0..218c1d0 100644 --- a/SourceCode/Code2026/Pool3dCmd/SBZWDlg.cpp +++ b/SourceCode/Code2026/Pool3dCmd/SBZWDlg.cpp @@ -44,7 +44,7 @@ namespace } break; default: - pXPData->m_pData = new T; + pXPData->m_pData = new unsigned char[sizeof(T)]; ::memcpy(pXPData->m_pData, pData, sizeof(T)); pXPData->m_nSize = sizeof(T); break; @@ -673,7 +673,7 @@ CSBZWDlg::CSBZWDlg(CWnd* pParent /*=NULL*/) m_boxData.m_eType = AecEqui::kBox; m_boxData.m_nID = ::_time32(NULL); - m_boxData.m_pData = new AecEqui::XBOX; + m_boxData.m_pData = new unsigned char[sizeof(AecEqui::XBOX)]; m_boxData.m_iClr = m_clr; AecEqui::XBox box; @@ -716,7 +716,7 @@ CSBZWDlg::CSBZWDlg(double dX, double dY, double dZ, CWnd *pParent /*=NULL*/) m_boxData.m_eType = AecEqui::kBox; m_boxData.m_nID = ::_time32(NULL); - m_boxData.m_pData = new AecEqui::XBOX; + m_boxData.m_pData = new unsigned char[sizeof(AecEqui::XBOX)]; m_boxData.m_iClr = m_clr; AecEqui::XBox box; @@ -932,7 +932,7 @@ Adesk::Int32 CSBZWDlg::AddNozz(DWORD dwSubiD, AcGeVector3d& vtDir, AcGePoint3d& data.m_nID = ::_time32(NULL); data.m_iClr = clr; - data.m_pData = new AecEqui::XNozz; + data.m_pData = new unsigned char[sizeof(AecEqui::XNozz)]; ::memcpy(data.m_pData, pNozzData, sizeof(AecEqui::XNozz)); data.m_nSize = sizeof(AecEqui::XNozz); data.m_nActiveInf = -1; diff --git a/SourceCode/Code2026/Pool3dCmd/makeValve.cpp b/SourceCode/Code2026/Pool3dCmd/makeValve.cpp index d270b60..6fe55ec 100644 --- a/SourceCode/Code2026/Pool3dCmd/makeValve.cpp +++ b/SourceCode/Code2026/Pool3dCmd/makeValve.cpp @@ -42,7 +42,7 @@ namespace MKValve } break; default: - pXPData->m_pData = new T; + pXPData->m_pData = new unsigned char[sizeof(T)]; ::memcpy(pXPData->m_pData, pData, sizeof(T)); pXPData->m_nSize = sizeof(T); break; @@ -1951,7 +1951,7 @@ namespace MKHvacValve } break; default: - pXPData->m_pData = new T; + pXPData->m_pData = new unsigned char[sizeof(T)]; ::memcpy(pXPData->m_pData, pData, sizeof(T)); pXPData->m_nSize = sizeof(T); break; diff --git a/SourceCode/Code2026/Pool3dCmd/makefengji.cpp b/SourceCode/Code2026/Pool3dCmd/makefengji.cpp index a60b2b6..8a1916e 100644 --- a/SourceCode/Code2026/Pool3dCmd/makefengji.cpp +++ b/SourceCode/Code2026/Pool3dCmd/makefengji.cpp @@ -83,7 +83,7 @@ namespace FENGJI } break; default: - pXPData->m_pData = new T; + pXPData->m_pData = new unsigned char[sizeof(T)]; ::memcpy(pXPData->m_pData, pData, sizeof(T)); pXPData->m_nSize = sizeof(T); break; diff --git a/SourceCode/Code2026/Pool3dCmd/pool3dcmdCmd.cpp b/SourceCode/Code2026/Pool3dCmd/pool3dcmdCmd.cpp index 39df404..164b1a5 100644 --- a/SourceCode/Code2026/Pool3dCmd/pool3dcmdCmd.cpp +++ b/SourceCode/Code2026/Pool3dCmd/pool3dcmdCmd.cpp @@ -6540,7 +6540,7 @@ void PL_FZGZCmd() data.m_nID = ::_time32(NULL); data.m_iClr = 1; - data.m_pData = new AecEqui::XNozz; + data.m_pData = new unsigned char[sizeof(AecEqui::XNozz)]; ::memcpy(data.m_pData, pNozzData, sizeof(AecEqui::XNozz)); data.m_nSize = sizeof(AecEqui::XNozz); data.m_nActiveInf = 0; diff --git a/SourceCode/Code2026/inc/AecDbEwEquipment.h b/SourceCode/Code2026/inc/AecDbEwEquipment.h index 42944d6..9590942 100644 --- a/SourceCode/Code2026/inc/AecDbEwEquipment.h +++ b/SourceCode/Code2026/inc/AecDbEwEquipment.h @@ -360,6 +360,8 @@ public: void AddSubPrimObj(AecEqui::XPrimData* p); void RemoveSubPrimObj(int nIndex); void RemoveSubPrimObjByID(int nSubID); + //释放全部几何单元(m_arSubPrimPtrs 里的 XPrimData 及其 m_pData) + void FreeSubPrimData(); void AddTransform(const AcGeMatrix3d& xform); void AddTransform(const AcGeVector3d& vtMove); diff --git a/SourceCode/Code2026/inc/EarThwormDef.h b/SourceCode/Code2026/inc/EarThwormDef.h index 6877302..2da8cf6 100644 --- a/SourceCode/Code2026/inc/EarThwormDef.h +++ b/SourceCode/Code2026/inc/EarThwormDef.h @@ -2538,30 +2538,19 @@ namespace AecEqui } ~XPrimData() { + releaseData(); for (size_t i(0); i < m_Combins.size(); ++i) DELETE_PTR(m_Combins[i]); } void releaseData() { - if (!m_pData) return; - switch (m_eType) - { - case AecEqui::kNewExtrude: - case AecEqui::kNewRevolve : - case AecEqui::kNewLoft: - case AecEqui::kRevitSweep: - case AecEqui::kNewSweep: - case AecEqui::kRevitCombination: - case AecEqui::kExtrude: - case AecEqui::kRevolve: - delete[] m_pData; - m_nSize = 0; - break; - default: - delete m_pData; - m_nSize = 0; - break; - } + //m_pData 一律用 new unsigned char[] 分配(dwgInFieldsForXPrim、byJson、 + //copyXPrimData 以及各命令模块的 setData),元素都是 POD,不含析构, + //所以释放规则只有一条:delete[]。不要再按 m_eType 区分。 + if (m_pData == NULL) return; + delete[] (unsigned char*)m_pData; + m_pData = NULL; + m_nSize = 0; } //基本体数据 short m_eType; //单元体类型