Delphi Berlin 10.1下JSON数据解析引发内存泄漏的问题求助
嘿,我来帮你排查这个Delphi JSON解析的内存泄漏问题!先看几个关键的泄漏点和修复方案:
你的代码里用TJSONObject.ParseJSONValue(s) as TJSONArray获取JSON数组,但如果解析出来的不是数组(比如是单个对象或字符串),as TJSONArray会返回nil,这时候你直接continue,但ParseJSONValue返回的原始TJSONValue对象还留在内存里,没有被释放!
修复方法:先把解析结果存到一个TJSONValue变量里,不管转换是否成功,都要释放这个变量:
var JSONValue: TJSONValue; JSONArray: TJSONArray; begin JSONValue := TJSONObject.ParseJSONValue(s); JSONArray := JSONValue as TJSONArray; if JSONArray = nil then begin ShowMessage('An error occurred reading the data file, section = [' + iniSection[tabpage] + '].'); JSONValue.Free; // 必须释放解析出来的对象 continue; end; try // 这里放你原来的循环处理逻辑 finally JSONArray.Free; // 或者用JSONValue.Free,两者效果一致,因为JSONArray是JSONValue的引用 end; end;
看你的代码里用了SL.Add(s)和SL.Clear,如果SL是你在这段代码里创建的(比如SL := TStringList.Create;),只调用Clear是不够的——Clear只是清空列表里的字符串,但TStringList对象本身的内存不会被回收。
修复方法:用try...finally包裹SL的创建和使用,确保最后释放:
var SL: TStringList; begin SL := TStringList.Create; try // 填充SL的代码:循环JSONArray添加ticker CombineStrings(sTickers, SL); // 用SL设置网格行等逻辑 finally SL.Free; // 彻底释放StringList end; end;
你在循环里多次写(JSONArray.Items[row - 1] as TJSONObject),可以把这个对象缓存到局部变量里,既提高代码效率,也让代码更整洁:
for row := 1 to SL.Count do begin var StockObj := JSONArray.Items[row - 1] as TJSONObject; //add fixed data to each grid row tabGrids[tabpage].Cells[0, row] := SL[row - 1]; tabGrids[tabpage].Cells[4, row] := StockObj.Get('qty').JSONValue.Value; tabGrids[tabpage].Cells[6, row] := StockObj.Get('cost').JSONValue.Value; tabGrids[tabpage].Cells[1, row] := StockObj.Get('name').JSONValue.Value; // 后面的tryStrToFloat等逻辑... end;
你担心的(JSONArray.Items[row] as TJSONObject).Get('ticker').JSONValue.Value这类语句的内存问题——其实完全不用怕,这些TJSONObject、TJSONPair、TJSONValue都是被JSONArray管理的,当你最后Free(JSONArray)的时候,所有子对象都会被自动释放,不需要手动单独释放它们。
内容的提问来源于stack exchange,提问作者Lorne Anderson

