使用SQLite DataReader读取数据时触发OutOfMemoryException求助
问题根源
就算设置了CommandBehavior.SequentialAccess,直接用dataReader["ColumnName"].ToString()或GetString()读取12MB级的大文本列时,还是会一次性把整个字段的字节数组加载到内存再转成字符串,多次累积后就触发了OutOfMemoryException。
解决步骤&代码修改
1. 先修正批量读取逻辑(如果是读20条记录)
原ExecuteReader<T>返回单个T,没法逐行释放内存,改成返回IEnumerable<T>,用yield return逐行处理:
public static IEnumerable<T> ExecuteReader<T>(string commandText, IEnumerable<QueryParameter> parameters, Func<IDataReader, T> parserMethod) { using (var command = SqliteDbProvider.FetchSqliteDbConnection().CreateCommand()) { AddQueryInCommand(commandText, parameters, command); using (var dataReader = command.ExecuteReader(CommandBehavior.SequentialAccess)) { // 逐行读,处理完一条就返回,避免内存堆积 while (dataReader.Read()) { yield return parserMethod(dataReader); } } } }
2. 用流分段读取大文本字段
替换原来直接读取列的方式,用GetStream()获取字段流,通过缓冲区分段构建字符串,避免一次性加载全部数据:
private static IResourceDefinition GetResourceDefinition(IDataReader dataReader) { // 先拿列索引,比用列名高效 int resourceDefColIndex = dataReader.GetOrdinal("ResourceDefinition"); int xmlDefColIndex = dataReader.GetOrdinal("XmlDefinition"); // 小字段正常读取 JObject jsonObject = JObject.Parse(dataReader.GetString(resourceDefColIndex)); // 大Xml字段分段读取 string xmlDefinition; const int bufferSize = 8192; // 8KB缓冲区,可根据内存情况调整 using (var stream = dataReader.GetStream(xmlDefColIndex)) using (var streamReader = new StreamReader(stream, Encoding.UTF8)) { StringBuilder sb = new StringBuilder(); char[] buffer = new char[bufferSize]; int readCount; while ((readCount = streamReader.Read(buffer, 0, bufferSize)) > 0) { sb.Append(buffer, 0, readCount); } xmlDefinition = sb.ToString(); } // 构建返回对象(示例) return new ResourceDefinition { ResourceData = jsonObject, XmlDefinition = xmlDefinition }; }
3. 注意事项
- 用
SequentialAccess必须按查询结果的列顺序读取,不能跳着读(比如先读XmlDefinition再读ResourceDefinition),当前代码的顺序是对的。 - 如果不需要完整的
XmlDefinition字符串,直接对流做解析处理(比如用XmlReader直接读流),能更省内存。
内容的提问来源于stack exchange,提问作者Manikandan Sekar
相关产品推荐
相关产品推荐

