我做了一个简单的系统来添加和删除EF Core数据库中的文件,如下所示:
-
添加文件 :
public async Task AddFile(IFileListEntry file) { File fileToAdd = await File.GetFileAsync(file); _context.Files.Add(fileToAdd); _context.SaveChanges(); }
-
从
IFileListEntry
接口获取文件,将文件包含在Stream
中:public static async Task<File> GetFileAsync(IFileListEntry file) { using MemoryStream ms = new MemoryStream(); await file.Data.CopyToAsync(ms); File f = new File { Name = file.Name, Type = file.Type, Size = file.Size, LastModified = file.LastModified, Data = ms.ToArray(), }; ms.Dispose(); return f; }
-
删除文件 :
public void DeleteFile(File file) { file.Data = new byte[0]; //Test _context.Files.Remove(file); _context.SaveChanges(); }
添加的所有文件都存储在List
中,并从中删除,列表本身包含在.razor
文件中(此处未显示,因为我认为这与我的问题无关(,也包含在EF Core数据库中。
数据库上下文_context
是通过 depedency 注入获得的,并从类继承DbContext
。
所以我的问题是:添加和删除文件后,我可以观察到内存泄漏,因为在将文件添加到数据库和列表中后,RAM 处于同一水平。
那我做错了什么?我真的不明白它可能来自哪里,因为MemoryStream
在使用后被处理掉,当文件被删除时,我会用一个空的,甚至是null
引用替换填充的byte[]
。我确保.razor
文件中的List
是一个新的空列表,我们再次用添加的文件填充该列表。不过我没有测试_context
。
我认为您的 DI 容器不会释放数据库上下文。
在此处查看数据库上下文文档
上下文的生存期从创建实例时开始,到实例被释放或垃圾回收时结束。如果您希望在块末尾释放上下文控制的所有资源,请使用 using。使用 using 时,编译器会自动创建一个 try/finally 块,并在 finally 块中调用 dispose。
public void UseProducts()
{
using (var context = new ProductContext())
{
// Perform data access using the context
}
}
如果上下文实例是由依赖项注入容器创建的,则容器通常负责释放上下文。
因此,如果您的 DI 不释放上下文,那么它会保留在内存中,因此看起来您有泄漏。
可能发生的另一件事是,垃圾回收不会发生可预测地检查此处的垃圾回收。因此,可能需要一些时间才能看到释放的内存。
最后一件事:你不需要ms.Dispose();
MemoryStream
此类型实现 IDisposable 接口,但实际上没有任何要释放的资源。这意味着不需要通过直接调用 Dispose(( 或使用语言构造(如 using (在 C# 中(或 Using(在 Visual Basic 中((来释放它。
所以MemoryStream
不会成为问题。