[英]Why is this code (possibly event handler) causing a memory leak in my c# windows service?
在 windows 服务中,我知道我有 memory 泄漏。 我怎么知道在这个问题的 scope 之外,但你可以在这里看到最初的问题
我有一些类的 windows 服务:
public partial class VLSService : ServiceBase
{
ReportedContentProcess reportedContent;
protected override void OnStart(string[] args)
{
//when a user reports a video
reportedContent = new ReportedContentProcess();
reportedContent.ProcessTimer.Elapsed += new ElapsedEventHandler(ReportedContentTimer_Elapsed);
}
void ReportedContentTimer_Elapsed(object sender, ElapsedEventArgs e)
{
reportedContent = new ReportedContentProcess();
reportedContent.Process();
reportedContent.ProcessReinstated();
}
}
public class ReportedContentProcess : ProcessBase
{
//location on the library
string libraryArchivedFilePath;
string libraryRealHiFilePath;
string libraryRealLoFilePath;
string libraryFlashHiFilePath;
string libraryFlashLoFilePath;
//location on the reported folder
string reportedContentArchivedFilePath;
string reportedContentRealHiFilePath;
string reportedContentRealLoFilePath;
string reportedContentFlashHiFilePath;
string reportedContentFlashLoFilePath;
string reportedContentFolderPath;
static EmailSettings emailSettings;
/// <summary>
/// This process will move reported content out of the 'real' and 'flash' mounted folders on the
/// hard drive/ storeage location so they cannot under any circumstances be got to by any users
/// of the library.
/// </summary>
public ReportedContentProcess(): base(1021)
{
DirectoryInfo arciveFolderPathInfo = new DirectoryInfo(fileSystemReferencesForService.ArchiveDir);
DirectoryInfo contentFolder = arciveFolderPathInfo.Parent;
reportedContentFolderPath = contentFolder.FullName.ToString() + @"\ReportedContent\";
emailSettings = settingsManagerForService.GetEmailSettings();
}
public override void Process()
{
if (!EnumsAndConstants.ApplicationLocks.ReportedContentProcessRunning)
{
EnumsAndConstants.ApplicationLocks.ReportedContentProcessRunning = true;
videosToProcess = contentManagerForService.GetReportedVideos(false);
//get the reportedvideo object for this video
CreateReportedVideoContentFolder();
ReportedVideo reportedVideo;
foreach (Video v in videosToProcess)
{
string flashVideoExt = string.Empty;
if (v.IsAudio)
{
flashVideoExt = ".mp3";
}
else
{
flashVideoExt = ".mp4";
}
//library location of each file for video
libraryArchivedFilePath = fileSystemReferencesForService.ArchiveDir + v.LocalFile;
libraryRealHiFilePath = fileSystemReferencesForService.RealDir + v.Url.ToString() + "_hi.rm";
libraryRealLoFilePath = fileSystemReferencesForService.RealDir + v.Url.ToString() + "_lo.rm";
libraryFlashHiFilePath = fileSystemReferencesForService.FlashDir + v.Url.ToString() + "_hi" + flashVideoExt;
libraryFlashLoFilePath = fileSystemReferencesForService.FlashDir + v.Url.ToString() + "_lo" + flashVideoExt;
//new location for file to go to
reportedContentArchivedFilePath = reportedContentFolderPath + v.LocalFile;
}
}
/// <summary>
/// A base class that holds all the Global objects for any process that operates under the
/// service. This process works with
/// </summary>
public abstract class ProcessBase
{
public Timer processTimer;
public Timer ProcessTimer{get{ return processTimer;}set{processTimer=value;}}
protected SqlConnection connection;
protected VlsContent contentManagerForService;
protected VlsSecurity securityManagerForService;
protected VlsSettings settingsManagerForService;
protected FileSystemReferences fileSystemReferencesForService;
protected List<Video> videosToProcess;
protected ExeReferences exeReferenecesForService;
protected GeneralSettings generalSettingsForService;
public abstract void Process();
//sets up all the common objects
public ProcessBase()
{
connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Db"].ToString());
contentManagerForService = new VlsContent(connection);
settingsManagerForService = new VlsSettings(connection);
securityManagerForService = new VlsSecurity(connection);
fileSystemReferencesForService = settingsManagerForService.GetFileSystemReferences();
exeReferenecesForService = settingsManagerForService.GetExeReferences();
generalSettingsForService = settingsManagerForService.GetGeneralSettings();
}
//This constructor will call the default constructor ^
protected ProcessBase(long intervalArg) : this()
{
processTimer = new Timer(intervalArg);
processTimer.Enabled = true;
}
}
在分析此代码后,这似乎导致了 memory 泄漏。 我想知道为什么?
我认为有问题的行是:
reportedContent = new ReportedContentProcess(); [located in the event handler]
但我真的不明白为什么。 当然,它会在 memory 中创建称为“reportedContent”的指针,然后当调用上述内容时,它将在堆上放置实际值,并为 ReportedContentProcess() 的成员提供新值。 然后,当事件处理程序在大约 1 秒后再次运行时,它会将 GC 根指针“reportedContent”替换为 ReportedContentProcess() class 的新分配堆项。 然后旧的(以及所有现在废弃的子对象将被垃圾收集,因为调用堆栈不再引用它们的根......?这应该一遍又一遍地发生(旧的和新的)风格.
希望有些人可以帮助我有点希望这是问题,所以我可以解决它,但想在开始重构代码之前检查。
简介在这里:
我不知道ProcessBase
是什么,但我认为这是您的问题所在。
它是否处理 .NET/C# 环境之外的任何内容? 它是否应该实现 IDisposable 接口,并且是否应该在创建新的ReportedProcess
之前释放现有的 ReportedProcess。
此外,您还为OnStart()
中的初始ReportedProcess
创建了一个事件处理程序。 然后,您通过为其引用分配一个新实例来丢失对第一个事件的引用,但是初始ReportedProcess
保持活动状态,因为它包含一个包含已订阅事件处理程序的 object,它不会被垃圾收集,直到程序结束,技术上是 memory 泄漏。
如果在ReportedProcess
class 的某个地方,您在清理事件处理程序方面应用相同的策略,那么您的问题就存在。
**更新的答案**
只是查看您更新的代码,它缺少 ProcessReinstated() 代码,但我认为这可能是您没有明确关闭您的 SqlConnection 的事实。 您的 ProcessBase 应该实现一个 IDisposable 接口,并且您的计时器代码应该在实例化新类之前显式处理现有的 ReportedProcess 类,这是数据库连接和 sockets 和其他外部连接之类的最佳策略。
它似乎没有 memory 泄漏。 有没有类似这样的代码:
reportedContent.ProcessTimer.Elapsed += new ElapsedEventHandler(ReportedContentTimer_Elapsed);
如果你有,那么你有一个对你创建的所有报告的Contect 的引用,并且 GC 不会释放它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.