Delphi 连接关闭后如何释放DataSnap内存?
我有一个TCP/IP DataSnap服务器作为服务[基于会话的生命周期]运行,它不断地消耗内存,即使没有连接,也永远不会恢复到起始内存大小 为了消除我的代码的罪魁祸首,我建立了一个基本TCP/IP DataSnap服务器的模型,该服务器作为VCL[基于会话的生命周期]运行,为服务器方法类[TDSServerModule]提供服务,该类只包含使用本机数据类型的基本数学函数[没有要创建或释放的对象] 当我用一个非常瘦的客户端连接到上述DataSnap服务器时,我得到了相同的结果。 每次连接时,内存使用量都会不断增加,从客户端执行服务器端方法时,内存使用量也会偶尔增加。一旦连接关闭,DataSnap服务器永远不会减少其内存使用量[即使在没有连接的情况下运行8小时] 关于为什么会发生这种情况,或者更重要的是如何减少这种情况,有什么建议吗 我正在使用RAD Studio XE2 Update 4修补程序1。让我引用一篇关于DataSnap的“必读”文章。这是关于XE3的,但我希望这里的代码也适用于XE2 内存消耗 我观察到的问题之一与内存消耗有关。如果调用的方法完全不执行任何操作,为什么Datasnap服务器会消耗这么多内存 也许我不知道如何准确地解释,但我会努力的。基本上,DataSnap为它接收的每个HTTP连接创建一个会话。该会话将在20分钟后被破坏,换句话说,在测试的前20分钟,内存消耗只会增加,之后它有稳定自身的趋势。我真的不知道为什么Datasnap会这样做。在REST应用程序中,我认为使用默认配置的这些会话没有多大意义。当然,会话可能会有所帮助,但我不明白为什么它是默认配置。事实上,DataSnap没有相应的配置。看起来您只需要使用这个会话控件,而不能选择其他方式(没有文档)。MORMot框架也有一个会话控件,但它是可配置的,并且不消耗太多内存 无论如何,有一种方法可以解决这个问题。Daniele Teti在他的博客上写了一篇文章“看一看”。我将在这里展示的解决方案是由他放在他的博客上的。谢谢Daniele 运行此方法后,会话将关闭,内存消耗将降低。当然,创建和销毁此会话仍然存在开销 因此,如果在XE2中可能的话,那么对您来说最好的方法就是用显式内存清理结束每个服务器方法。然后,您最好再次阅读这些文章,并为将来的可伸缩性挑战做好准备Delphi 连接关闭后如何释放DataSnap内存?,delphi,memory-leaks,delphi-xe2,datasnap,Delphi,Memory Leaks,Delphi Xe2,Datasnap,我有一个TCP/IP DataSnap服务器作为服务[基于会话的生命周期]运行,它不断地消耗内存,即使没有连接,也永远不会恢复到起始内存大小 为了消除我的代码的罪魁祸首,我建立了一个基本TCP/IP DataSnap服务器的模型,该服务器作为VCL[基于会话的生命周期]运行,为服务器方法类[TDSServerModule]提供服务,该类只包含使用本机数据类型的基本数学函数[没有要创建或释放的对象] 当我用一个非常瘦的客户端连接到上述DataSnap服务器时,我得到了相同的结果。 每次连接时,内存
- 让我引用一篇关于DataSnap的“必读”文章。这是关于XE3的,但我希望这里的代码也适用于XE2
内存消耗
我观察到的问题之一与内存消耗有关。如果调用的方法完全不执行任何操作,为什么Datasnap服务器会消耗这么多内存
也许我不知道如何准确地解释,但我会努力的。基本上,DataSnap为它接收的每个HTTP连接创建一个会话。该会话将在20分钟后被破坏,换句话说,在测试的前20分钟,内存消耗只会增加,之后它有稳定自身的趋势。我真的不知道为什么Datasnap会这样做。在REST应用程序中,我认为使用默认配置的这些会话没有多大意义。当然,会话可能会有所帮助,但我不明白为什么它是默认配置。事实上,DataSnap没有相应的配置。看起来您只需要使用这个会话控件,而不能选择其他方式(没有文档)。MORMot框架也有一个会话控件,但它是可配置的,并且不消耗太多内存
无论如何,有一种方法可以解决这个问题。Daniele Teti在他的博客上写了一篇文章“看一看”。我将在这里展示的解决方案是由他放在他的博客上的。谢谢Daniele
运行此方法后,会话将关闭,内存消耗将降低。当然,创建和销毁此会话仍然存在开销
因此,如果在XE2中可能的话,那么对您来说最好的方法就是用显式内存清理结束每个服务器方法。然后,您最好再次阅读这些文章,并为将来的可伸缩性挑战做好准备
然后,应用程序将显示关闭datasnap服务器时发生的内存泄漏。您应该检查servercontainer上TDSServerclass组件的Lifecycle属性。它提供了一种确定会话处理方式的方法。它默认为会话。将其设置为invokation将在每次调用(invokation)后释放会话。这当然意味着你没有国家。不过,这在一个典型的REST服务器中是可行的 如果内存消耗仍在增长。在dpr单元中放置以下行。 ReportMemoryLeaksOnShutdown:=True
然后,应用程序将显示关闭datasnap服务器时发生的内存泄漏。我添加了以下方法,并从“TWebModule1::WebModuleBeforeD”调用了它
uses System.StrUtils, DataSnap.DSSession, Data.DBXPlatform;
function TServerMethods1.HelloWorld: String;
begin
Result := 'Hello World';
GetInvocationMetaData.CloseSession := True;
end;
// ---------------------------------------------------------------------------
/// <summary> Memory Restoration. DataSnap opens a session for each call
/// even when the service is set for invocation.
/// Sessions are building up consuming memory and seem not to be freed.
/// See: https://stackoverflow.com/questions/17748300/how-to-release-datasnap-memory-once-connections-are-closed
/// </summary>
/// <remarks> Iterates session in the session manager and closes then terminates
/// any session that has been idle for over 10 seconds.
/// </remarks>
/// <returns> void
/// </returns>
// ---------------------------------------------------------------------------
void TWebModule1::CloseIdleSessions()
{
TDSSessionManager* sessMgr = TDSSessionManager::Instance;
int sessCount = sessMgr->GetSessionCount();
WriteLogEntry(LogEntryTypeDebug, "TWebModule1::CloseIdleSessions", "Session Count: " + IntToStr(sessCount));
TStringList* sessKeys = new TStringList;
sessMgr->GetOpenSessionKeys(sessKeys);
WriteLogEntry(LogEntryTypeDebug, "TWebModule1::CloseIdleSessions", "Session Keys Count: " + IntToStr(sessKeys->Count));
TDSSession* sess = NULL;
for(int index = 0; index < sessKeys->Count; index++)
{
String sessKey = sessKeys->Strings[index];
sess = sessMgr->Session[sessKey];
unsigned elapsed = (int)sess->ElapsedSinceLastActvity();
if(elapsed > 10000)
{
WriteLogEntry(LogEntryTypeDebug, "TWebModule1::CloseIdleSessions", "CloseSession TerminateSession Key: " + sessKey);
sessMgr->CloseSession(sessKey);
sessMgr->TerminateSession(sessKey);
}
sess = NULL;
}
delete sessKeys;
sessMgr = NULL;
}