![]() |
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. |
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. |
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. |
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:
Sie müssen nicht bei jeder Anfrage an den Server aufgerufen werden.
initialization
CoInitialize(nil); finalization CoUninitialize; end. Ansonsten hab' ich an Deinem prinzipiellen Aufbau des Webmodules nix auszusetzen, allerdings solltest Du eventuell bei Methoden wie
Delphi-Quellcode:
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
procedure TWebModuleMain.tcmGet(Request: TWebRequest;
Response: TWebResponse);
Delphi-Quellcode:
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.
Response.SendResponse;
|
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 ? |
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? |
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. |
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 :-/ |
AW: WebModule & ADOConnection in Service -> Speicherübrelauf
Zitat:
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:
Damit bin ich bisher immer auf der sicheren Seite gewesen.
myquery.close;
myquery.SQL.text='select Kontonummer from yourtable where userid=12345'; myquery.open; {-- holen oder nicht holen ----------------------------} myquery.close; Gruß K-H |
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:
Eventuell bekommst Du das Problem ja dann hiermit weg:
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.
Delphi-Quellcode:
initialization
CoInitFlags := COINIT_MULTITHREADED; CoInitialize(nil); finalization CoUninitialize; end. |
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. |
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:
gemacht wurde und in der DPR die erste Zeile hinter dem begin
initialization
CoInitialize(nil); finalization CoUninitialize; end.
Delphi-Quellcode:
lautet.
CoInitFlags := COINIT_MULTITHREADED;
Habe jedenfalls in meinem Fundus keine funktionierende ISAPI-Dll bzw. kein funktionierendes CGI-Programm, die/das ADO nutzt und der Aufruf anders geregelt ist. |
AW: WebModule & ADOConnection in Service -> Speicherübrelauf
Zitat:
Zitat:
|
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. |
AW: WebModule & ADOConnection in Service -> Speicherübrelauf
Zitat:
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:
Ich vermute mal, dass CoInitialize da nicht so ganz threadsave ist, da die Aufrufe ja allem Anschein nach weitere Verbindungen irgendwie beeinflussen.
begin
CoInitFlags := COINIT_MULTITHREADED; CoInitialize(nil); Application.Initialize; Application.CreateForm(Application.CreateForm(Twm, wm); Application.Run; CoUninitialize; end. 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: ![]() Hab' mal die Sourcen einer funktionierenden ISAPI-Dll angehängt, eventuell kannst Du damit ja was anfangen. |
AW: WebModule & ADOConnection in Service -> Speicherübrelauf
Zitat:
|
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: |
AW: WebModule & ADOConnection in Service -> Speicherübrelauf
Alternative:
Delphi-Quellcode:
Funktioniert so leider auch nicht. Bekomme dann die Exception das CoInitialize nicht aufgerufen wurde.
begin
CoInitFlags := COINIT_MULTITHREADED; CoInitialize(nil); Application.Initialize; Application.CreateForm(Application.CreateForm(Twm, wm); //Initialisierungen hier zwischen... Application.Run; CoUninitialize; end. 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. |
AW: WebModule & ADOConnection in Service -> Speicherübrelauf
Momentan hab' ich da keine Idee mehr, nur was zum Lesen:
![]() ![]() ![]() 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 ![]() |
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 :) |
AW: WebModule & ADOConnection in Service -> Speicherübrelauf
Hmm..
Zitat:
Lt.: ![]() 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.. |
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. |
AW: WebModule & ADOConnection in Service -> Speicherübrelauf
Hmm..
Zitat:
Vielleicht kümmert sich ja die ISAPIThreadPool dann um die COM-Verwaltung ?!? |
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. |
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 :) |
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 |
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 ![]() 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 ![]() 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? ![]() 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 ( ![]() |
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