2

我有一个 TCP/IP DataSnap 服务器作为服务 [基于会话的 LifeCycle] 运行,它不断地消耗内存,即使没有连接到它,也永远不会回到起始内存大小。

为了消除我的代码作为罪魁祸首,我已经建模了一个基本的 TCP/IP DataSnap 服务器作为 VCL [基于会话的 LifeCycle] 运行,它服务于一个服务器方法类 [TDSServerModule],它只包含使用本机数据类型的基本数学函数 [没有要创建或释放的对象]。

当我使用非常瘦的客户端连接到所述 DataSnap 服务器时,我得到了相同的结果。内存使用随着每个连接不断增长,并且在从客户端执行服务器端方法时偶尔增长。一旦连接关闭,DataSnap 服务器永远不会减少其内存使用量[即使在没有连接的情况下运行 8 小时]。

关于为什么会发生这种情况或更重要的是如何减少它的任何建议?

我正在使用 RAD Studio XE2 Update 4 HotFix 1。

4

3 回答 3

2

让我引用一篇关于 DataSnap 的“必读”文章。这是关于 XE3 但我希望这里的代码也适用于 XE2。

内存消耗

我观察到的问题之一与内存消耗有关。如果调用的方法完全不执行任何操作,为什么 Datasnap 服务器会消耗这么多内存?

也许我不知道如何准确解释,但我会尝试。基本上,DataSnap 会为它接收到的每个 HTTP 连接创建一个会话。这个会话会在20分钟后被销毁,也就是说,在测试的前20分钟内存消耗只会增加,之后有趋于稳定的趋势。我真的不知道为什么 Datasnap 会这样做。在 REST 应用程序中,使用默认配置的这些会话没有多大意义。当然,会话可能会有所帮助,但我不明白为什么它是默认配置。实际上,DataSnap 并没有针对此的配置。看起来您只需要使用此会话控件,而无法选择其他方式(没有文档)。MORMot 框架也有一个会话控制,但它是可配置的并且不会消耗太多内存。

无论如何,有办法解决这个问题。Daniele Teti 在他的博客上写了一篇文章,看看。我将在这里展示的解决方案是由他放在他的博客上的。谢谢丹尼尔。

uses System.StrUtils, DataSnap.DSSession, Data.DBXPlatform;

function TServerMethods1.HelloWorld: String;
 begin

 Result := 'Hello World';
 GetInvocationMetaData.CloseSession := True;
end;

运行此方法后,会话将关闭,内存消耗将降低。当然仍然存在创建和销毁此会话的开销。

因此,如果在 XE2 中可行的话,对您来说最好的方法似乎是使用显式内存清理来结束每个服务器方法。那你最好再读一遍这些文章,为未来的可扩展性挑战做好准备。

于 2013-07-19T23:03:44.253 回答
2

我添加了以下方法并从“TWebModule1::WebModuleBeforeDispatch”事件中调用它。它消除了内存消耗,实际上允许空闲的 REST 服务返回到无会话内存的状态。DataSnap 肯定需要解决这个问题。

// ---------------------------------------------------------------------------
/// <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;
}
于 2021-02-26T15:37:37.337 回答
1

您应该检查服务器容器上 TDSServerclass 组件的 Lifecycle 属性。它提供了一种确定会话处理方式的方法。它默认为会话。将其设置为调用将在每次调用(调用)后释放会话。这当然意味着你没有状态。不过,这在典型的 REST 服务器中是可以的。

如果您的内存消耗仍在增长。将以下行放入您的 dpr 单元中。ReportMemoryLeaksOnShutdown := True;
然后,您的应用程序将向您显示关闭 datasnap 服务器时的内存泄漏。

于 2013-08-21T12:51:07.980 回答