Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 连接关闭后如何释放DataSnap内存?_Delphi_Memory Leaks_Delphi Xe2_Datasnap - Fatal编程技术网

Delphi 连接关闭后如何释放DataSnap内存?

Delphi 连接关闭后如何释放DataSnap内存?,delphi,memory-leaks,delphi-xe2,datasnap,Delphi,Memory Leaks,Delphi Xe2,Datasnap,我有一个TCP/IP DataSnap服务器作为服务[基于会话的生命周期]运行,它不断地消耗内存,即使没有连接,也永远不会恢复到起始内存大小 为了消除我的代码的罪魁祸首,我建立了一个基本TCP/IP DataSnap服务器的模型,该服务器作为VCL[基于会话的生命周期]运行,为服务器方法类[TDSServerModule]提供服务,该类只包含使用本机数据类型的基本数学函数[没有要创建或释放的对象] 当我用一个非常瘦的客户端连接到上述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中可能的话,那么对您来说最好的方法就是用显式内存清理结束每个服务器方法。然后,您最好再次阅读这些文章,并为将来的可伸缩性挑战做好准备

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

      内存消耗

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

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

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

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

      因此,如果在XE2中可能的话,那么对您来说最好的方法就是用显式内存清理结束每个服务器方法。然后,您最好再次阅读这些文章,并为将来的可伸缩性挑战做好准备


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

      如果内存消耗仍在增长。在dpr单元中放置以下行。 ReportMemoryLeaksOnShutdown:=True

      然后,应用程序将显示关闭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;
      }