我有这个方法从.dbf文件中读取:
public DataTable ReadBulkDBF(string dbfFile, Dictionary<string, string> columnKeys, int maxRows, string dynamicValue, int nextId)
{
long start = DateTime.Now.Ticks;
DataTable dt = new DataTable();
BinaryReader recReader;
string number;
string year;
string month;
string day;
long lDate;
long lTime;
DataRow row;
int fieldIndex;
bool foundLastColumn = false;
List<string> keys = new List<string>(columnKeys.Keys);
List<string> values = new List<string>(columnKeys.Values);
// For testing purposes
int rowCount = 0;
// If there isn't even a file, just return an empty DataTable
if ((!File.Exists(dbfFile)))
{
return dt;
}
BinaryReader br = null;
try
{
// Will allow shared open as long as the other application using it allows it too.
// Read the header into a buffer
br = new BinaryReader(File.Open(dbfFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
byte[] buffer = br.ReadBytes(Marshal.SizeOf(typeof(DBFHeader)));
// Marshall the header into a DBFHeader structure
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
DBFHeader header = (DBFHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(DBFHeader));
handle.Free();
// Read in all the field descriptors. Per the spec, 13 (0D) marks the end of the field descriptors
ArrayList fields = new ArrayList();
while ((13 != br.PeekChar()))
{
buffer = br.ReadBytes(Marshal.SizeOf(typeof(FieldDescriptor)));
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
fields.Add((FieldDescriptor)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(FieldDescriptor)));
handle.Free();
}
// Read in the first row of records, we need this to help determine column types below
((FileStream)br.BaseStream).Seek(header.headerLen + 1, SeekOrigin.Begin);
buffer = br.ReadBytes(header.recordLen);
recReader = new BinaryReader(new MemoryStream(buffer));
// Create the columns in our new DataTable
DataColumn col = null;
dt.Columns.Add(new DataColumn("updateId", typeof(int)));
if (!dbfFile.Contains("con_compania")) { dt.Columns.Add(new DataColumn("dynamic", typeof(string))); }
dt.Columns.Add(new DataColumn("fechasync", typeof(DateTime)));
foreach (FieldDescriptor field in fields)
{
// Adds columns to DataTable dt
}
// Skip past the end of the header.
((FileStream)br.BaseStream).Seek(header.headerLen, SeekOrigin.Begin);
// Read in all the records
for (int counter = 0; counter < header.numRecords && dt.Rows.Count < maxRows; counter++)
{
// First we'll read the entire record into a buffer and then read each field from the buffer
// This helps account for any extra space at the end of each record and probably performs better
buffer = br.ReadBytes(header.recordLen);
recReader = new BinaryReader(new MemoryStream(buffer));
// All dbf field records begin with a deleted flag field. Deleted - 0x2A (asterisk) else 0x20 (space)
if (recReader.ReadChar() == '*')
{
continue;
}
// Loop through each field in a record
fieldIndex = 2;
rowCount = dt.Rows.Count;
row = dt.NewRow();
foreach (FieldDescriptor field in fields)
{
switch (field.fieldType)
{
// Casts field's value according to its type and saves it in the dt.
}
fieldIndex++;
}
// Looks for key-value combination in every row until
// it finds it to know where to start reading the new rows.
if (!foundLastColumn && columnKeys.Keys.Count > 0)
{
foundLastColumn = true;
int i = 3;
if (dbfFile.Contains("con_compania")) { i = 2; }
for (; i < keys.Count && foundLastColumn; i++)
{
if (!row[keys[i]].ToString().Equals(values[i]))
{
foundLastColumn = false;
}
}
}
else
{
dt.Rows.Add(row);
nextId++;
}
}
}
catch (Exception e)
{
throw e;
}
finally
{
if (null != br)
{
br.Close();
br.Dispose();
}
}
long count = DateTime.Now.Ticks - start;
return dt;
}
问题出在某个地方我会留下某种参考,所以我得到了OOM。
使用类似的方法调用该方法:
DataTable dt = new ParseDBF().ReadBulkDBF(...);
//Use dt
dt.Dispose();
dt = null;
如果我只调用Dispose()它会保留引用,如果我调用null dt变为null,但是对ParseDBF对象的引用仍然存在。
知道泄漏可能在哪里?我已经在互联网上寻找想法,并尝试调用Dispose()和Close(),并设置为null我使用它之后我能想到的一切,并且它一直在发生。
答案 0 :(得分:1)
我注意到重新加载者可能没有被释放。
我强烈建议在此代码中使用块来确保在执行离开使用范围时清除IDisposable对象。