Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   WebModule & ADOConnection in Service -> Speicherübrelauf (https://www.delphipraxis.net/191419-webmodule-adoconnection-service-speicheruebrelauf.html)

markusef 13. Jan 2017 13:31

WebModule & ADOConnection in Service -> Speicherübrelauf
 
Hallo,

aktuell sitze ich an einem Client - Server Projekt.

Zum Server:
Als erstes setzte ich den Webservice auf (TWebmodule in einen Win-Service gebettet). Dieser beantwortet diverse Get Anfragen je nach Action (Parameter) und sucht die jeweiligen Daten aus einer Datenbank heraus (die sich ebenfalls auf dem Server befindet). Bei jeder Action wird eine TADOConnection created, eine TADOQuery created, belegt und genutzt. Anschließend geschlossen und mit einem FreeAndNil beseitigt.
Soweit funktioniert auch alles recht fix und wie gewollt.

Zum Client:
Firemonkey Crossplatform App, fragt Daten vom Webservice via Delphi RESTClient/RESTRequest/RESTResponse ab, macht seinen Job wie gewollt.

Zum Problem:
Der Client fragt in festen Zyklen Daten vom Webservice ab, nun fiel mir auf das die Arbeitsspeicherauslastung des Webservices (im Task Manager als .exe angezeigt) von Request zu Request steigt.
Allerdings wird in jeder Action des Webservices wie oben bereits beschrieben alles sachgemäßig (meiner Meinung nach) geschlossen und bereinigt.

*Nebenbemerkung:
Wenn ich die ADOConnection weglasse, kann ich tausende Anfragen in ein paar Sekunden generieren und bekomme auch eine Antwort ohne das die Arbeitsspeicherauslastung auch nur um 100kb nach oben steigt.

Ich habe bereits versucht mit FastMM der Sache auf den Grund zu gehen, allerdings bisher erfolglos. :pale:

Habt ihr zufällig Ideen woran das liegen könnte ?
Ist evtl. das gesamte Konstrukt eher ungünstig ? Bin ein wenig ratlos, programmiere das erste mal eine Client-Server Anwendung. :?:
Bisher waren die serverseitigen Komponenten bereits immer vorhanden.

nahpets 13. Jan 2017 13:41

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Quelltext?

So ist es eher ein Raten mit Hilfe der :glaskugel:

Wenn Du die ADOConnetion weglassen kannst und das Ganze auch ohne die funktioniert, dann lass sie doch weg, sie wird ja dann wohl nicht benötigt.

Bei den ADO-Komponenten kann man entweder eine ADOConnection zuweisen oder einen Connectionstring angeben.

Wenn der angegeben ist, kann die ADOConnection entfallen. Sollte in dem WebService nur eine ADO-Komponente sein, so kann sie die Verbindung problemlos selbst herstellen.

Eine ADOConnection ist eigentlich nur dann sinnvoll, wenn man mehrere ADO-Komponenten nutzt und sie alle über eine Verbindung laufen sollen.

markusef 13. Jan 2017 13:57

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Okay, wieder was gelernt mit der ADOConnection. :roll:
Grundlegend und simpel gesagt will ich pro Action was aus der Datenbank holen, schick verpacken und als Response an den Client senden.
Also könnte ich demnach eine TADOQuery pro Action mit einem ConnectionString abfeuern ?

Desweiteren fiel mir auf das, sobald der REST Client eine Anfrage schickt, in der Klasse Webmodule in das WebModuleCreate gesprungen wird, allerdings nur bei der ersten Anfrage, bei allen weiteren nicht.
Sobald der REST Client fertig ist bleibt demnach (so vermute ich) die Instanz des Webmodules bestehen.
Destroy wird erst ausgelöst wenn ich den Service komplett schließe.

*nicht wundern, es ist erstmal nur ein Testaufbau, deshalb teilweise die sinnlosen Variablenbelegungen.

Code:

TWebModuleMain = class(TWebModule)
    //--------------------------------------------------------------------------
    //Webservice für HTTP Requests
    //--------------------------------------------------------------------------
    //Default Web Handler, liefert HTML Rumpf für "ungewöhnliche" Anfragen
    procedure WebModule3DefaultHandlerAction   ( Sender: TObject;
                                                  Request: TWebRequest;
                                                  Response: TWebResponse;
                                                  var Handled: Boolean);

    //Webhandler für Requests
    procedure WebModuleMaintcmAction           ( Sender: TObject;
                                                  Request: TWebRequest;
                                                  Response: TWebResponse;
                                                  var Handled: Boolean);

    procedure WebModuleCreate(Sender: TObject);
    procedure WebModuleDestroy(Sender: TObject);

  private
    { Private-Deklarationen }

    procedure getNothing       ( Request: TWebRequest; Response: TWebResponse); //test für memory leak
    procedure send501(text : String);

  public
    { Public-Deklarationen }
  end;

var
  WebModuleClass : TComponentClass = TWebModuleMain;


implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}

{$R *.dfm}

//Default path (no path infos, only url + port)
procedure TWebModuleMain.WebModule3DefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  Response.Content :=
    '<html>' +
    '<head><title>Webserver-Anwendung</title></head>' +
    '<body>Test Webservice'+
    '</body>' +
    '</html>';
end;

procedure TWebModuleMain.WebModuleCreate(Sender: TObject);
var
  test : STring;
begin
  test := 'abcdef';
end;

procedure TWebModuleMain.WebModuleDestroy(Sender: TObject);
var
  Test : String;
begin
  Test := 'abcerf';
end;

procedure TWebModuleMain.WebModuleMaintcmAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  Handled := true;
  case Request.MethodType of
    mtGet:     tcmGet( Request, Response );
    mtPut:     send501('this function was not implemented');
    mtPost:    send501('this function was not implemented');
    mtDelete:  send501('this function was not implemented');
    else begin
      send501('this function was not implemented');
    end;
  end;
end;

procedure TWebModuleMain.getNothing(Request: TWebRequest;
  Response: TWebResponse);
var
  tst : String;
  ADOConnection : TADOConnection;
  ADOQuery     : TADOQuery;
begin
  try
    CoInitialize(nil);
    ADOConnection := TADOConnection.Create(nil);
    ADOConnection.ConnectionString := 'Provider=MSDASQL.1;Password=CASS2HAR;Persist Security Info=True;User ID=ADMIN;Data Source=MaxDb_GOLD1';
    ADOQuery := TADOQuery.Create(nil);
    ADOQuery.Connection := ADOConnection;

    ADOConnection.Connected := true;

    ADOQuery.SQL.Text := 'SELECT Name, Age FROM customer WHERE id=1';

    ADOQuery.Open;
    ADOQuery.First;

    tst := tst + ADOQuery.FieldByName('name').AsString;
    Response.StatusCode := 200;
    Response.Content := tst;
  finally
    FreeAndNil(ADOQuery);
    ADOConnection.Connected := false;
    FreeAndNil(ADOConnection);
    CoUninitialize;
  end;
end;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Help Classes
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


procedure TWebModuleMain.tcmGet(Request: TWebRequest;
  Response: TWebResponse);
begin
  if not Request.QueryFields.Values['action'].IsEmpty then
  begin
    if Request.QueryFields.Values['action'] = 'getnothing' then
    begin
      getNothing(Request, Response);
    end;

´   //Mehr Actionhandling..
  end;
end;

procedure TWebModuleMain.send501(text : String);
begin
  Response.StatusCode := 501;
  Response.ContentType := 'text/plain';
  Response.Content := text;
  Response.SendResponse;
end;

end.

nahpets 13. Jan 2017 14:25

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Meine letzten Webmodule sind schon 'ne Weile her, daher nur so aus dem Gedächtnis:

ADO-Komponenten habe ich auf das Webmodul gepappt. Sie werden beim Create des Webmoduls erstellt und beim Destroy wieder weggeräumt.

Habe sie also nicht bei jeder Anfrage an den Server erstellt und nach erledigter Arbeit freigegeben. Allerdings weiß ich nicht, inwieweit dieses mein Vorgehen threadsave ist.

Dein Vorgehen könnte da durchaus sinnvoller sein.

Wenn Du nur eine ADOQuery nutzt, benötigst Du keine ADOConnection, es reicht, wenn die ADOQuery den Connctionstring erhält.

Das CoInitialize(nil); und das CoUninitialize; stecken bei mir am Ende der Unit unter:
Delphi-Quellcode:
initialization
  CoInitialize(nil);

finalization
  CoUninitialize;

end.
Sie müssen nicht bei jeder Anfrage an den Server aufgerufen werden.

Ansonsten hab' ich an Deinem prinzipiellen Aufbau des Webmodules nix auszusetzen, allerdings solltest Du eventuell bei Methoden wie
Delphi-Quellcode:
procedure TWebModuleMain.tcmGet(Request: TWebRequest;
  Response: TWebResponse);
noch 'nen Try-Except-Block einfügen, damit Du bei Fehlern eine gescheite Fehlermeldung an den Client schicken kannst. Es muss sichergestellt sein, dass alles das, was Du in der Methode Send501 befüllst, immer gefüllt ist und (egal was passiert) am Ende ein erfolgreiches
Delphi-Quellcode:
Response.SendResponse;
steht. Ansonsten kann es passieren, das Webserver und/oder Client irgendwann ins Stolpern geraten. Und dann den Fehler suchen müssen, ist nicht wirklich spaßig.

markusef 13. Jan 2017 14:38

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Okay, ja ein vernünftiges Exception Handling muss da definitiv noch rein, da hast du recht.
Das Daten abfragen mit der ADOQuery funktioniert auch so einwandfrei, Danke für den Tipp, das spart Quelltext.

Allerdings ist das Problem leider noch nicht behoben, mit jeder Anfrage steigt die Arbeitsspeicherauslastung des Services echt enorm, sinkt aber nach beendigung aller Anfragen auch nicht mehr :?:

Woran kann das denn noch liegen ?
Könnte es sein das man die Webmodule nicht in einem Windows Service benutzen sollte ?

Habe mir da schon die Finger wund-gegooglet und überall werden die Webmodule nur in .dlls für IIS oder Apache genutzt :roll:

*EDIT:

CoInitialize(nil) & CoUni.. kann ich leider nicht in den jeweiligen Part für "initialization" und "finalization" packen, dann wirft mir Delphi vor ich hätte CoInitialize nicht aufgerufen :-/

*EDIT EDIT:

Grundlegende Frage: Wird, wenn sich ein Client mit dem Service verbindet, je Client ein WebModule Instanz erzeugt ? Oder pro Anfrage (auch vom selbem Client, weis ja nicht ob die Delphi Komponente sich das merkt) ?
Falls ja, wieso wird nachdem der RESTClient expliziert Disconnect aufruft die jweilige Instanz nicht abgeschossen ?

Jumpy 13. Jan 2017 14:55

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Hast du mal geschaut, ob vllt. bei jeder Request ein neues Webmodul erstellt wird? Wenn du das nicht so verwendest, wie es gedacht ist, könnte das doch sein?

OK, hast in deinem EditEdit ja die selbe Idee Edith :)

Vllt. zeigst du uns mal den Code des Services, wo das Webmodul eingebettet ist?

nahpets 13. Jan 2017 14:56

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Meckert Delphi auch noch, wenn Du die beiden Co...Dingens ins Create bzw. Destroy packst?

Bei mir (mit Delphi 7) gab es von Delphi immer schimpfe, wenn ich es nicht bei "initialization" und "finalization" reingepackt hatte, sondern sonstwo.

Habe Webmodule nur in DLLs und CGIs für meinen Webserver genutzt. Ob das in 'nem Service nicht nutzbar ist, weiß ich nicht.
Aber eigentlich ist Dein Service doch das gleiche wie 'ne Exe plus DLL in "eins zusammengepackt" ;-)

Beim fünften mal Lesen Deines Quelltextes fiel mir was auf, weiß aber nicht, ob das Problem daher kommen könnte:

Auf ein ADOQuery.Open folgt kein ADOQuery.Close.

markusef 13. Jan 2017 15:07

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Also anscheinend wird beim erstmaligen verbinden eine Instanz von TWebModule angelegt, danach (vorerst) keine weitere. Ich habe einen Testclient gebaut welcher eine Anfrage schickt, auf ein Response wartet und wenn ein Response ankam gleich den nächsten Request abschickt. Dann rutschte er zu Beginn zwei mal in die WebModuleCreate und anschließend lief alles im Alleingang (hatte beim Debugen nur einen Haltepunkt in der Create und in der Destroy), Destroy wurde auch erst bei Beendigung des kompletten Services ausgeführt.
Irgendwas ist da mächtig Faul :shock:

CoInitialize(nil) und CoUnitialize war auch mein nächster Tipp im Create, das funktioniert auch, komischerweise aber nur bis zu einem bestimmten Punkt, ab einer gewissen Anzahl von Anfragen wirft er mir plötzlich trotzdem eine Exception das CoInitialize nicht aufgerufen wurde.

ADOQuery.Close verhalf leider auch nicht zum gewünschten Erfolg :-/

p80286 13. Jan 2017 15:37

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Zitat:

Zitat von nahpets (Beitrag 1358814)
Auf ein ADOQuery.Open folgt kein ADOQuery.Close.

Au backe das kann Mecker geben!
in meinen Anfangszeiten hab ich mir das Close solange geschenkt, bis das ich gemerkt habe, daß das der beste Weg zu ganz feinem Datenhack ist. Darum sehen meine Queries immer so aus:
Delphi-Quellcode:
myquery.close;
myquery.SQL.text='select Kontonummer from yourtable where userid=12345';
myquery.open;
{-- holen oder nicht holen ----------------------------}
myquery.close;
Damit bin ich bisher immer auf der sicheren Seite gewesen.

Gruß
K-H

nahpets 13. Jan 2017 15:38

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Das wird jetzt irgendwie etwas seltsam:

Jetzt kommt von mir mal nur vermuteter Spekulatius ohne Gewähr.

Meine mal gelesen zu haben, dass pro Client ein Webmodul erstellt wird. Also müsste pro Client auch einmal Create aufgerufen werden.

Bei der Verwendung von HTTP können (meine ich jedenfalls) zwischen einem Client und einem Server zwei Verbindungen aufgebaut werden. Dies würde das zweimalige Aufrufen von Create bei Nutzung eines Testclients erkären.

Was passiert, wenn Du den Testclient mehrfach startest. Erhöht sich die Anzahl der Create-Aufrufe dann?

Wenn ja, dann packe die ADOQuery mal auf das Webmodule, statt sie bei 'ner Anfrage selbst zu erstellen und wieder freizugeben.

Wird das Webmodule pro Client erstellt, dürfte es dann auch (kaum) zu Konflikten kommen, wenn mehrere Anfragen unterschiedlicher Clients zeitgleich beim Service ankommen.

Das mit dem CoIni-Dingens kann ich (nicht) verstehen.

Wenn das für die ganze Applikation gilt, dürfte bei wiederholten Anforderungen an den Service mit jeweiligen Aufrufen von CoInitialize und CoUninitialize und gleichzeitigen Anfragen mehrere Clients hier ein bisserl "Durcheinander" entstehen. Es ist ja nicht sichergestellt, dass die Anfragen vollständig nacheinander "abgearbeitet" werden.

Habe bei meinen ISAPI-Dlls erst dann Ruhe gehabt, nachdem ich die Aufrufe nach initialization bzw. finalization verschoben hatte.

Mal noch 'ne andere Idee:

Kannst Du die beiden Aufrufe nicht irgendwo außerhalb des Webmoduls im Service unterbringen?

Oder, nachdem ich mal in alte Quellen geguckt habe, in der DPR zu eine ISAPI-Dll steht dashier:
Delphi-Quellcode:
library WebSQLSearch;

uses
  ActiveX,
  ComObj,
  ISAPIThreadPool,
  ISAPIApp,
  BrkrConst in '..\..\..\Delphi7\Source\Internet\BrkrConst.pas',
  WebBroker in '..\..\..\Delphi7\Source\Internet\WebBroker.pas',
  WebSQLSearchUnit1 in 'WebSQLSearchUnit1.pas' {wm: TWebModule};

{$R *.res}

exports
  GetExtensionVersion,
  HttpExtensionProc,
  TerminateExtension;

begin
  CoInitFlags := COINIT_MULTITHREADED; // <--- Hast Du das irgendwo untergebracht?
  Application.Initialize;
  Application.CreateForm(Twm, wm);
  Application.Run;
end.
Eventuell bekommst Du das Problem ja dann hiermit weg:
Delphi-Quellcode:
initialization
  CoInitFlags := COINIT_MULTITHREADED;
  CoInitialize(nil);

finalization
  CoUninitialize;

end.

HolgerX 13. Jan 2017 18:20

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Hmm..

Hab noch kein Webmodul erstellt, also in blaue...

Wenn dein

getNothing(

in seinem eignen Thread aufgerufen wird, dann muss immer das CoInitialize und das CoUninitialize im getNothing( gemacht werden, sprich da , wo mit den ADOs gearbeitet wird!

Jeder Thread muss sein eigenes CoInitialize machen, deshalb geht das (globale) CoInitialize im Initialization nicht.

nahpets 13. Jan 2017 18:28

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Mein praktische Erfahrung mit dutzenden von ISAPI-Dlls ist bisher: Es geht nur, wenn es so
Delphi-Quellcode:
initialization
  CoInitialize(nil);

finalization
  CoUninitialize;

end.
gemacht wurde und in der DPR die erste Zeile hinter dem begin
Delphi-Quellcode:
  CoInitFlags := COINIT_MULTITHREADED;
lautet.

Habe jedenfalls in meinem Fundus keine funktionierende ISAPI-Dll bzw. kein funktionierendes CGI-Programm, die/das ADO nutzt und der Aufruf anders geregelt ist.

Olli73 15. Jan 2017 13:31

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Zitat:

Zitat von markusef (Beitrag 1358815)
Also anscheinend wird beim erstmaligen verbinden eine Instanz von TWebModule angelegt, danach (vorerst) keine weitere. Ich habe einen Testclient gebaut welcher eine Anfrage schickt, auf ein Response wartet und wenn ein Response ankam gleich den nächsten Request abschickt. Dann rutschte er zu Beginn zwei mal in die WebModuleCreate und anschließend lief alles im Alleingang (hatte beim Debugen nur einen Haltepunkt in der Create und in der Destroy), Destroy wurde auch erst bei Beendigung des kompletten Services ausgeführt.
Irgendwas ist da mächtig Faul :shock:

Da ist nix faul. Es wird ein Pool von WebModule-Instanzen erstellt: Bei mehreren gleichzeitigen Anfragen, werden neue Instanzen erstellt, die bleiben dann auch erhalten und jede neue Anfrage wird an eine dieser Instanzen geschickt.

Zitat:

Zitat von markusef (Beitrag 1358815)
CoInitialize(nil) und CoUnitialize war auch mein nächster Tipp im Create, das funktioniert auch, komischerweise aber nur bis zu einem bestimmten Punkt, ab einer gewissen Anzahl von Anfragen wirft er mir plötzlich trotzdem eine Exception das CoInitialize nicht aufgerufen wurde.

CoInitialize sollte nur 1 mal zu Beginn aufgerufen werden. Daher nicht im Create des Webmodule aufrufen, da das ja mehrfach geschehen kann.

markusef 16. Jan 2017 08:12

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Hallo,

erstmal danke für die zahlreichen Antworten, ich war am Wochenende leider nicht da.
Also das Flag wurde gesetzt (CoInitFlags := COINIT_MULTITHREADED) in der ersten Zeile unterhalb von 'begin' in der der dpr.
Weiterhin wurde CoInitialize(nil) und CoUninitialize nochmals in 'initialization' & 'finalization' eingefügt. Starte ich den Service nun, wirft er mir bei der Nutzung der ADO eine Exception das CoInitialize nicht verwendet wurde.

Das Speicherüberlauf-Problem ist leider immer noch vorhanden, an der rohen TWebModule Instanz kann es nicht liegen, lasse ich (testweise) die Verbindung zur DB sein und kommentiere diese aus, dann kann ich locker 2000 Anfragen in ein paar Sekunden stellen ohne das der Arbeitsspeicher auch nur mit der Wimper zuckt. Demnach muss es irgendwas mit der ADO Connection zu tun haben.

Ich würde ja auch eine andere DB Verbindungsart testen, weis aber ehrlich gesagt bei einer MaxDB (SAP) nicht was ich sonst für eine Verbindung nutzen kann, zumal ich bisher mit der ADOConnection sehr gut gefahren bin.

@nahpets: wenn ich weitere Instanzen des Clients starte (auf der selben Maschine) dann wird keine neue Verbindung erstellt, ich denke mal du wirst recht haben mit den zwei Verbindungen. Habe ich drei bis vier Instanzen offen bekomme ich auch Exceptions das dass Datenbankobjekt mehrfach genutzt wird, demnach stimmt die Theorie soweit das er pro IP/Client ein WebModule erstellt da ja in diesem Fall mehrere Clients ein WebModule "genutzt" haben.

nahpets 16. Jan 2017 11:48

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Zitat:

Zitat von markusef (Beitrag 1358901)
nochmals

oder nur?

CoInitialize(nil) und CoUninitialize dürfen nur einmalig aufgerufen werden. Nicht pro Verbindung und nicht pro Client und nicht pro Anfrage, sondern insgesamt nur einmal.

Bei 'ner ISAPI-Dll ist das durch den Aufruf in initialization und finalization sichergestellt. Weiß nicht, ob das bei 'nem Service auch so ist, würd' es aber doch stark vermuten. Schlimmstenfalls mal bei jedem Aufruf der beiden Routinen 'nen Eintrag in 'ne Logdatei machen, um so zu prüfen, wie oft man da vorbeikommt.

Alternative:
Delphi-Quellcode:
begin
  CoInitFlags := COINIT_MULTITHREADED;
  CoInitialize(nil);
  Application.Initialize;
  Application.CreateForm(Application.CreateForm(Twm, wm);
  Application.Run;
  CoUninitialize;
end.
Ich vermute mal, dass CoInitialize da nicht so ganz threadsave ist, da die Aufrufe ja allem Anschein nach weitere Verbindungen irgendwie beeinflussen.

Wenn alle Stricke reißen, dann mal die ganze Verbindung von CoInitialize über Verbindung zur Datenbank und Ausführung der Abfrage, bis CoUninitialize mit 'ner TCriticalSection kapseln. Allerdings scheint mir das dann nicht so wirklich im Sinne des Erfinders zu sein.

Eventuell findest Du hier ja weitere Hinweise: https://www.benefind.de/web.php?org=...+thread+delphi

Hab' mal die Sourcen einer funktionierenden ISAPI-Dll angehängt, eventuell kannst Du damit ja was anfangen.

Jumpy 16. Jan 2017 12:08

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Zitat:

Zitat von Jumpy (Beitrag 1358813)
Vllt. zeigst du uns mal den Code des Services, wo das Webmodul eingebettet ist?

Wie siehts denn damit aus? Vielleicht liegt es ja am drum herum (plus die ADO-Komponenten)?

markusef 16. Jan 2017 12:59

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
"Nochmals" war schon richtig, hatte die Idee mit der initialization / finalization bereits probiert, leider funktioniert es dort nicht.
Werde es jetzt nochmal direkt in der .dpr testen, sprich den von dir geschilderten Ablauf, andernfalls werde ich mir die .dll mal zu gemüte führen, schon mal ein riesen Danke im voraus !!! :)

An dem "drumherum" kann es nicht liegen da es ohne die ADOConnection problemlos läuft und kein Arbeitsspeicherüberlauf eintritt, das ist ja das verwunderliche, zumal ich die ADOConnection so gut wie immer verwende und das immer in diesem Service-Template (man tippt ja ungern doppelt :-P), nur eben zum ersten mal mit einem WebModule :shock:

Werde mich dann mit weiteren Infos melden wenn es Neuigkeiten gibt.
Danke für eure Hilfe bis jetzt :thumb::wink:

markusef 16. Jan 2017 13:24

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Alternative:
Delphi-Quellcode:
begin
  CoInitFlags := COINIT_MULTITHREADED;
  CoInitialize(nil);
  Application.Initialize;
  Application.CreateForm(Application.CreateForm(Twm, wm);
  //Initialisierungen hier zwischen...
  Application.Run;
  CoUninitialize;
end.
Funktioniert so leider auch nicht. Bekomme dann die Exception das CoInitialize nicht aufgerufen wurde.

Die Initialisierung des Webmodules erfolgt in der .dpr:

Code:
program TCMWebservice;

uses
  ActiveX,
  System.Win.ComObj,
  Vcl.SvcMgr,
  SysUtils,
  StrUtils,
  Web.WebReq,
  IdHTTPWebBrokerBridge,
  srvMain in 'srvMain.pas' {GFSRestWebservice: TService},
  serviceConsts in 'serviceConsts.pas',
  ModDb in 'modules\ModDb.pas' {DataModule1: TDataModule},
  ModWebModule in 'modules\ModWebModule.pas' {WebModuleMain: TWebModule},
  ModSessionHandler in 'modules\ModSessionHandler.pas' {SessionHandler: TDataModule};

{$R *.RES}
var
  sName    : String;
  DBConInit : TDataModule1;

begin
  if not Application.DelayInitialize or Application.Installing then
    Application.Initialize;


  if WebRequestHandler <> nil then
  begin
    WebRequestHandler.WebModuleClass := WebModuleClass;
  end;
  Application.CreateForm(TTCMRestWebservice, TCMRestWebservice);
  Application.CreateForm(TSessionHandler, SessionHandler);
  try

    sName := ExtractFileName (ParamStr (0));
    sName := AnsiReplaceText (sName, ExtractFileExt (sName), '');

    TCMRestWebservice.Name       := sName;
    TCMRestWebservice.DisplayName := sName;

    sName := EmptyStr;

    Application.Run;
  except
  on E: Exception do

  end;
end.

nahpets 16. Jan 2017 13:44

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Momentan hab' ich da keine Idee mehr, nur was zum Lesen: MSDN - CoInitialize function

When do I need to call CoInitialize() in this scenario?

Multithreaded Delphi Database Queries

Ob dort eine Lösung zu finden ist, vermag ich nicht zu sagen.

Edit:

Was mir da gerade noch so einfällt:

Statt ADO die ZeoLib nutzen. Sie kann auch mit ADO umgehen und damit auch über ODBC auf was auch immer zugreifen.

markusef 16. Jan 2017 14:26

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Okay werd ich mir direkt mal anschauen ! Danke für die Infos und die Hilfe :thumb:
Sobald es neues gibt werde ich mich hier melden :)

HolgerX 16. Jan 2017 18:21

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Hmm..


Zitat:

Zitat von nahpets (Beitrag 1358938)

CoInitialize(nil) und CoUninitialize dürfen nur einmalig aufgerufen werden. Nicht pro Verbindung und nicht pro Client und nicht pro Anfrage, sondern insgesamt nur einmal.

Nicht ganz richtig..

Lt.:

https://msdn.microsoft.com/de-de/lib...(v=vs.85).aspx

MUSS CoInitialize(nil) und CoUninitialize JE Thread aufgerufen werden wenn COM verwendet werden soll, was bei ADO nun mal so ist.

Wenn jede Anfrage über das WebModule in einem eigenen Sub-Thread ausgeführt wird, muss auch in der Execute des Threads CoInitialize(nil) und CoUninitialize aufgerufen werden.

Auch kannst Du mehrfach CoInitialize aufrufen, musst nur jeweils auch ein CoUninitialize dazu machen.

Ob es bei einer ISAPI-Dll anders ist, oder ob diese DLL immer nur aus einem Thread (MainThread) aufgerufen wird.. k.A.

Jedoch deuten die Fehlermeldungen von seinem ADO-Aufruf darauf hin, dass diese in einem eigenen Thread aufgerufen werden und somit expliziert CoInitialize brauchen.
Warscheinlich sind die ADOs eben nicht ThreadSave und somit eventuell von CoInitFlags := COINIT_MULTITHREADED ausgenommen..

nahpets 16. Jan 2017 18:35

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Also den Fehler mit dem CoIni ... nicht aufgerufen hab' ich bei den ISAPI-Dlls erst dann wegbekommen wenn ich

1. ISAPIThreadPool in die Uses der DPR
2. CoInitFlags := COINIT_MULTITHREADED hinter das Begin der DPR
3. CoInitialize(nil); ins initialization des Webmoduls
4. CoUninitialize; ins finalization des Webmoduls

gepackt habe.

Und ja, es widerspricht allen Dokumentationen.

HolgerX 16. Jan 2017 18:43

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Hmm..


Zitat:

Zitat von nahpets (Beitrag 1359010)
Also den Fehler mit dem CoIni ... nicht aufgerufen hab' ich bei den ISAPI-Dlls erst dann wegbekommen wenn ich

1. ISAPIThreadPool in die Uses der DPR
2. CoInitFlags := COINIT_MULTITHREADED hinter das Begin der DPR
3. CoInitialize(nil); ins initialization des Webmoduls
4. CoUninitialize; ins finalization des Webmoduls

gepackt habe.

Und ja, es widerspricht allen Dokumentationen.

OK, dann sollte er mal prüfen, ob er es genau so gemacht hat.
Vielleicht kümmert sich ja die ISAPIThreadPool dann um die COM-Verwaltung ?!?

nahpets 16. Jan 2017 19:48

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Das Teil ISAPIThreadPool ist irgendwie dafür verantwortlich, dass das Multithreading in 'nem Webserver mit ISAPI-Dlls überhaupt funktioniert.

Und hier wird im konkreten Fall ja eine Webserver erstellt, der mehrere Anfragen von mehreren Clients zeitgleich verarbeiten können muss.

Eventuell sollte man sich die Unit mal genauer anschauen und prüfen, was dort so alles geschieht, was im zu erstellenden Service (und seinen genutzten Units) nicht vorhanden ist.

CoInitializeEx und CoUninitialize werden in der Unit u. a. auch aufgerufen.

markusef 17. Jan 2017 11:17

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Neuer Stand:

ich werde das ganze Projekt jetzt doch als .dll für einen IIS aufbauen. Bezüglich der ADO/Webmodule/Service-Geschichte gab es einfach keine Fortschritte und auch (aus meiner Sicht) keine Anhaltspunkte mehr um das ganze Zeitnah zu realisieren.

Mit der .dll unter IIS funktioniert das einwandfrei, danke an der Stelle nochmal an naphets, das war ein super Beispiel zum orientieren ! :thumb:
Ist zwar jetzt ein wenig umständlicher zu handhaben, aber es geht zumindest und das auch sehr performant !

Wenn mal wieder Luft ist werde ich natürlich weiter versuchen das ganze als Service zu realisieren (sowas kann man ja nicht auf sich beruhen lassen :-P).
Falls euch noch was einfallen sollte, ich werde den Thread dennoch regelmäßig besuchen & updates geben wenn ich an der Problematik weiter getüfftelt habe :)

markusef 19. Jan 2017 10:36

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Also mit der .dll klappt das soweit wunderbar.
Allerdings wächst der Arbeitsspeicher für die w3wp.exe die die isapi dll nutzt pro Anfrage auch ziemlich schnell ins unermessliche. Nachdem ich die Verbindung des Clients beende bleibt die w3wp.exe einfach bei der Größe stehen und es passiert auch nichts weiter.
Irgendwo mache ich demnach etwas falsch, ich weis aber beim besten Willen nicht was.

Muss ich noch dafür sorgen das die WebModule Threads nach abarbeitung beendet werden ? Ich dachte eigentlich das die Threadverwaltung vom IIS Manager übernommen wird

nahpets 19. Jan 2017 12:43

AW: WebModule & ADOConnection in Service -> Speicherübrelauf
 
Das wird jetzt schwierig, da ich mit dem IIS keinerlei Erfahrung habe. Habe meinen eigenen Webserver (mit den Indy-Komponenten) erstellt. Mit dem nutze ich seit Jahren Isapi-Dlls, auch solche, die ADO nutzen. Habe dort bisher keinen Speicherzuwachs feststellen können. Die DLLs sind alle so aufgebaut, wie in meinem Beispiel. Es gibt also nichts zum Aufräumen ...

Frage: Musst Du ADO nutzen?

Hast Du schonmal mit den Zeos-Komponenten gearbeitet?
Dort kann man auch die ADO-Schnittstelle nutzen.
(Zuletzt hier http://www.delphipraxis.net/191453-z...ml#post1359230 behandelt.)

Bleibt mit denen das Problem erhalten? Wenn nein, würde ich es in den ADO-Komponenten suchen und auf Zeos wechseln.

Eine (langsamere) Alternative:

Erstelle bitte eine neue CGI-Anwendung.
Entferne aus dieser das Webmodul.
Füge das Webmodul Deiner ISAPI-Dlls hinzu.
Im Idealfall hast Du nun (ohne weitere Änderungen) eine CGI-Anwendung mit identischem Funktionsumfang.

Kannst Du diese mit dem IIS nutzen?
Ändert sich etwas, außer dem Laufzeitverhalten?

Was ändert sich bei der w3wp.exe und/oder dem IIS noch?
Neben dem Speicherverbrauch, Handles? Threads? Benutzerobjekte?
Gibt es in der DLL eventuell Speicherlöcher?

Liefert Dir der https://www.heise.de/download/produc...explorer-21841 eventuell genauere Informationen.

Könntest Du bitte den aktuellen Quellcode Deiner momentanen Fassung (dpr und pas) hier posten? Eventuell kann man ja was sehen.
Je nach Umfang könnte ich mal schauen, ob ich sie auf eine eigene Datenbank umkonfigurieren kann und dann mal mit meinem Webserver testen.

Sind hier eventuell hilfreiche Informationen zur Problemlösung zu finden?
http://help.sap.com/saphelp_nw73ehp1...a/frameset.htm

Eine weitere Frage, eher mal so in den Raum geworfen, in der Hoffnung, dass irgendwer aus dem Forum sie beantworten kann:

Der Zugriff auf MaxDB von SAP ist per ODBC, JDBC, SQLDBC (http://open-maxdb-group.org/components/interfaces/) möglich. Welche Zugriffsmöglichkeiten gibt es hier bei aktuellen Delphis, ohne über die ADO-Schnittstelle zu gehen? Gibt es sie überhaupt?


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:09 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz