使用Delphi TJSONObject和TJSONArray时出现内存泄漏或访问违规
问题根源与修复方案
核心问题
- JSON对象所有权错误:
jobject2是jobject的子对象,Delphi的TJSONObject会自动管理子节点的内存。你手动调用jobject2.Free后,jobject在后续释放时会尝试再次释放已经被销毁的jobject2,直接触发访问违规(Access Violation)。 - 内存泄漏的本质:原代码中当
isScanDataB为true时,只释放了jobject2,却没有释放根对象jobject,导致jobject及其未被手动释放的子节点内存泄漏;而注释掉scanNumberI分支后,你释放了jobject,泄漏自然消失,但恢复分支后因为提前释放子对象,引发AV。
修复后的代码
使用try...finally确保根对象jobject一定会被释放,同时完全移除对子对象的手动释放操作:
function TtrackingsingleDlog.getJsonValue(const isScanDataB: boolean; scanNumberI: integer; pairnameS, fullStringS: string): string; var jobject: TJSONObject; jobject2: TJSONObject; scansarray: TJSONArray; valueStringS: string; begin valueStringS := ''; jobject := TJSONObject.ParseJSONValue(fullStringS) as TJSONObject; try if isScanDataB then begin // 先判断jobject是否有效,避免空指针访问 if Assigned(jobject) and jobject.TryGetValue('data', jobject2) then begin if scanNumberI >= 0 then begin if Assigned(jobject2) and jobject2.TryGetValue('scans', scansarray) then begin // 确保数组索引有效,避免越界 if (scanNumberI >= 0) and (scanNumberI < scansarray.Count) then begin scansarray[scanNumberI].TryGetValue<string>(pairnameS, valueStringS); end; end; end else begin if Assigned(jobject2) then begin jobject2.TryGetValue(pairnameS, valueStringS); end; end; end; end else begin if Assigned(jobject) then begin jobject.TryGetValue(pairnameS, valueStringS); end; end; Result := valueStringS; finally // 只释放根对象,子对象会被自动清理 jobject.Free; end; end;
关键优化点
- 新增
Assigned()判断,避免空指针访问(比如ParseJSONValue可能返回nil) - 使用
try...finally块确保jobject无论代码执行路径如何都会被释放,彻底杜绝内存泄漏 - 移除所有
jobject2.Free调用,交给根对象jobject统一管理子节点内存 - 增加数组索引有效性判断,避免数组越界访问
内容的提问来源于stack exchange,提问作者user2580203
相关产品推荐
相关产品推荐

