[Gelöst] fin.exe Memory nimmt zu

27. April 2009 10:14

Hallo zusammen,¨

nach längerem erfolglosen Suchen, habe ich mich entschlossen, doch einen Eintrag zu eröffnen.

Ich erstelle mit einem Batchjob sehr viele PDF-Dateien (Archivierungslösung). Nach jedem Datensatz mache ich einen Update des gelesenen Datensatzes.
Nach ungefähr 1'000 erstellten PDFs stürzt mir aber der Client ab. Der Server meldet "Sie haben nicht genügend Speicher, um diese Funktion auszuführen".

Ich habe nun im Windows Task gesehen, dass der zugeteilte Hauptspeicher der fin.exe von Minute zu Minute zunimmt. Dies geht solange gut, bis der Server selber wohl nicht mehr genügend RAM zur Verfügung stellen kann. Dem Datenbankdienst sind nur 100 MB zugeteilt. Die fin.exe hat aber schon jetz über 200 MB zugeteilt!?!

Wie kann ich dieses Problem umgehen oder beheben? Irgenwie müsste ich doch verhindern können, dass der zugeteilte Hauptspeicher immer mehr anwächst.
In meiner Codeunit habe ich nach jeder PDF-Erstellung einen COMMIT eingebaut.

Ich mache wohl einen Überlegungsfehler (es ist Montag) und wäre dankbar für wertvolle Tipps.

Vielen Dank, Beno.
Zuletzt geändert von beno am 3. Mai 2011 16:44, insgesamt 1-mal geändert.

Re: fin.exe Memory nimmt zu

27. April 2009 10:21

Klingt nach einer endlosen Rekursion, könnte das sein?

Re: fin.exe Memory nimmt zu

27. April 2009 10:25

Hört sich für mich auch eher danach an, als würdest du in deiner Programmierung Variablen (z.B. temporäre Records) nicht leeren oder Endlosschleifen erzeugen.

Re: fin.exe Memory nimmt zu

27. April 2009 10:28

Werden in diesem Report Bitmaps angezeigt?

Gruss

Re: fin.exe Memory nimmt zu

27. April 2009 10:29

Also ein Loop ist es definitiv nicht! Pro Datensatz wird eine PDF-Datei und eine Index-Datei erstellt. Für die rund 1'000 verarbeiteten Datensätze sind 1'000 unterschiedliche PDF- und Index-Dateien erstellt worden. Ich rufe aber in der Codeunit pro Datensatz eine Funktion innerhalb der Codeunit auf. Diese Funktion ruft dann eine andere Codeunit auf, welche... etc. etc. etc.
Müsste ich hier jeweils etwas schliessen? Oder was meint ihr mit temporären Records?

Re: fin.exe Memory nimmt zu

27. April 2009 10:33

Ja, bei den zu archivierenden Reports handelt es sich um Rechnungen, Gutschriften, etc. Beim Druck wird z.B. ein "grauer Balken", welcher in einer Tabelle als BLOB hinterlegt ist, in der Titelzeile des Ausdrucks ausgegeben.

Re: fin.exe Memory nimmt zu

27. April 2009 10:33

beno hat geschrieben:Müsste ich hier jeweils etwas schliessen?

Ohne einen Blick auf deinen Quelltext schwer zu sagen ...

Oder was meint ihr mit temporären Records?

Das war nur ein abstraktes Beispiel, weil ich ja nicht weiß, ob du Records mit der Eigenschaft Temporary = yes verwendest.

Re: fin.exe Memory nimmt zu

27. April 2009 10:35

beno hat geschrieben:Ich rufe aber in der Codeunit pro Datensatz eine Funktion innerhalb der Codeunit auf. Diese Funktion ruft dann eine andere Codeunit auf, welche... etc. etc. etc.

Ich würde tippen, dass du dort suchen musst. Möglicherweise rennen diese Aufrufe im Kreis; sprich: irgendwann landen diese Aufrufe wieder am Anfang, und dann geht alles von vorne los.

Re: fin.exe Memory nimmt zu

27. April 2009 10:36

Sag mir einfach, wo ich den Code hinschicken soll.

Re: fin.exe Memory nimmt zu

27. April 2009 10:42

Edit: War ein Missverständnis :-(
Zuletzt geändert von McClane am 27. April 2009 11:10, insgesamt 1-mal geändert.

Re: fin.exe Memory nimmt zu

27. April 2009 10:46

Code wird hier im Forum veröffentlicht und dabei so formatiert:
[code]Dein Codeblock 1[/code]
Hier dein Text zum Code
[code]Dein Codeblock 2[/code]

Bevor du das tust, würde ich an deiner Stelle noch einmal selbst suchen:
Debugger starten (ohne Breakpoint auf Triggern), deine Funktion starten.
Dort, wo der Debugger aufgrund eines Fehlers angehalten ist, einen Breakpoint setzen (ich nehme an: eine bestimmte Funktion).
Das Ganze Prozedere wiederholen: Wie oft wird deine Funktion wiederholt aufgerufen? Kommt dir etwas verdächtig vor?

Re: fin.exe Memory nimmt zu

27. April 2009 10:47

Also wie schon gesagt, ein Loop kann ich ausschliessen. Es wird nicht immer wieder von vorne begonnen. Aber vielleicht habe ich mit RecordRef und FieldRef Mist gebaut.
Wenn jemand von Euch einen kurzen Blick auf den Code werfen möchte, sagt mir einfach, wohin ich ihn schicken soll.
Merci, Beno

Re: fin.exe Memory nimmt zu

27. April 2009 10:48

Die Bitmaps sind ein Problem, wenn viele Datensätze mit einem Report.Run oder Report.Runmodal gedruckt werden.
Wenn der Report für jeden Datensatz einzeln aufgerufen wird und nachher mit Clear wieder freigegeben wird, sollte es kein Problem sein.

Re: fin.exe Memory nimmt zu

27. April 2009 10:49

beno hat geschrieben:Wenn jemand von Euch einen kurzen Blick auf den Code werfen möchte, sagt mir einfach, wohin ich ihn schicken soll.

Dies habe ich dir einen Beitrag über deinem erläutert.

Re: fin.exe Memory nimmt zu

27. April 2009 10:56

Okay, hier ein paar Ausschnitte aus dem Code (ist sonst viel zu lange):

Code:
IF recSalesInvHeaderG.FIND('-') THEN
  REPEAT
    OrderTypeG := recSalesInvHeaderG.FIELDNO("Order Type");
    NumberG := recSalesInvHeaderG.FIELDNO("No.");
    RecordRefG.GETTABLE(recSalesInvHeaderG);
    recReportSelectionG.RESET;
    recReportSelectionVehicleG.RESET;
    CASE recSalesInvHeaderG."Order Type" OF
      recSalesInvHeaderG."Order Type"::"Parts Sales & Purchases":
        BEGIN
          pgmDocumentPrintG.setRepSelFilter(recReportSelectionG, recReportSelectionG.Usage::"S.Inv.",
            recSalesInvLineG.GetMakeForDocPrint(recSalesInvHeaderG."No.", recSalesInvHeaderG."Make Code"),
            recSalesInvHeaderG."Location Code");
          IF recReportSelectionG.FIND('-') THEN
            REPEAT
              funWindreamArchiveG(RecordRefG,OrderTypeG,NumberG,recObjectG.Type::Report,recReportSelectionG."Report ID");
            UNTIL recReportSelectionG.NEXT = 0;
        END;
      recSalesInvHeaderG."Order Type"::"Vehicle Sales & Purchases",
      recSalesInvHeaderG."Order Type"::Service:
        BEGIN
          IF recSalesInvHeaderG."Order Type" = recSalesInvHeaderG."Order Type"::"Vehicle Sales & Purchases" THEN
            pgmDocumentPrintG.setVehicleRepSelFilter(recReportSelectionVehicleG, recReportSelectionVehicleG.Usage::"VK-RG",
              recSalesInvLineG.GetMakeForDocPrint(recSalesInvHeaderG."No.", recSalesInvHeaderG."Make Code"),
              recSalesInvHeaderG."Location Code")
          ELSE
            pgmDocumentPrintG.setVehicleRepSelFilter(recReportSelectionVehicleG, recReportSelectionVehicleG.Usage::"WS-RG",
              recSalesInvLineG.GetMakeForDocPrint(recSalesInvHeaderG."No.", recSalesInvHeaderG."Make Code"),
              recSalesInvHeaderG."Location Code");
          IF recReportSelectionVehicleG.FIND('-') THEN
            REPEAT
              funWindreamArchiveG(RecordRefG,OrderTypeG,NumberG,recObjectG.Type::Report,recReportSelectionVehicleG."Report ID");
            UNTIL recReportSelectionVehicleG.NEXT = 0;
        END;
    END;
  UNTIL (recSalesInvHeaderG.NEXT = 0);

Dies ist der Steuerblock. Mit jedem Datensatz wird die Funktion funWindreamArchiveG aufgerufen.

Code:
funWindreamArchiveG(RecordRefL : RecordRef;OrderTypeL : Integer;NumberL : Integer;ObjectTypeL : Integer;ReportIDL : Integer)
pgmGlobal.ÜbergabeFilter(RecordRefL.GETVIEW);
TableIDL := RecordRefL.NUMBER;

//Update Fortschrittsfenster
IF GUIALLOWED THEN BEGIN
  ProgressCounterG += 1;
  WindowG.UPDATE(2,ROUND(ProgressCounterG * 10000 / ProgressFactorG,1));
  WindowG.UPDATE(1,FORMAT(RecordRefL.CAPTION));
  IF RecordRefL.FIELDEXIST(OrderTypeL) THEN
    WindowG.UPDATE(4,FORMAT(RecordRefL.FIELD(OrderTypeL)) + ' ' + FORMAT(RecordRefL.FIELD(NumberL)))
  ELSE
    WindowG.UPDATE(4,FORMAT(RecordRefL.FIELD(NumberL)));
  CASE TableIDL OF
    DATABASE::"Sales Invoice Header",
    DATABASE::"Sales Credit Memo Header",
    DATABASE::"Issued Reminder Header":
      BEGIN
        CASE TableIDL OF
          DATABASE::"Sales Invoice Header":
            BEGIN
              ProgressCounterSalesInvG += 1;
              WindowG.UPDATE(3,ROUND(ProgressCounterSalesInvG * 10000 / ProgressFactorSalesInvG,1));
            END;
          DATABASE::"Sales Credit Memo Header":
            BEGIN
              ProgressCounterSalesCredG += 1;
              WindowG.UPDATE(3,ROUND(ProgressCounterSalesCredG * 10000 / ProgressFactorSalesCredG,1));
            END;
          DATABASE::"Issued Reminder Header":
            BEGIN
              ProgressCounterIssRemG += 1;
              WindowG.UPDATE(3,ROUND(ProgressCounterIssRemG * 10000 / ProgressFactorIssRemG,1));
            END;
          END;
      END;
    DATABASE::"Purch. Invoice Header",
    DATABASE::"Purch. Credit Memo Header":
      BEGIN
        CASE TableIDL OF
          DATABASE::"Purch. Invoice Header":
            BEGIN
              ProgressCounterPurchInvG += 1;
              WindowG.UPDATE(3,ROUND(ProgressCounterPurchInvG * 10000 / ProgressFactorPurchInvG,1));
            END;
          DATABASE::"Purch. Credit Memo Header":
            BEGIN
              ProgressCounterPurchCredG += 1;
              WindowG.UPDATE(3,ROUND(ProgressCounterPurchCredG * 10000 / ProgressFactorPurchCredG,1));
            END;
          END;
      END;
    DATABASE::"Vendor Ledger Entry":
      BEGIN
        ProgressCounterVendLedgEntryG += 1;
        WindowG.UPDATE(3,ROUND(ProgressCounterVendLedgEntryG * 10000 / ProgressFactorVendLedgEntryG,1));
      END;
  END;
END;

recObjectL.Type := ObjectTypeL;
EVALUATE(ObjectTypeTextL,FORMAT(recObjectL.Type));
CASE ObjectTypeL OF
  recObjectL.Type::Report: IF NOT pgmWD.HasParameterEntry(ObjectTypeTextL + FORMAT(ReportIDL),1,0) THEN EXIT;
  recObjectL.Type::Table:  IF NOT pgmWD.HasParameterEntry(ObjectTypeTextL + FORMAT(TableIDL),1,0) THEN EXIT;
  ELSE EXIT;
END;

//Archivieren
CASE TableIDL OF
  DATABASE::"Sales Invoice Header",
  DATABASE::"Sales Credit Memo Header",
  DATABASE::"Issued Reminder Header":     
    pgmWD.DruckeReportArchivAusgang(TableIDL,0,FORMAT(RecordRefL.FIELD(NumberL)),
      ReportIDL,pgmWD.GetDocTypeParameterEntry(ObjectTypeTextL + FORMAT(ReportIDL),1,0));
  DATABASE::"Purch. Invoice Header",
  DATABASE::"Purch. Credit Memo Header":
    pgmWD.DruckeReportArchivEingang(TableIDL,0,FORMAT(RecordRefL.FIELD(NumberL)),
      ReportIDL,pgmWD.GetDocTypeParameterEntry(ObjectTypeTextL + FORMAT(ReportIDL),1,0));
  DATABASE::"Vendor Ledger Entry":
    BEGIN
      RecordID2L := RecordRefL.RECORDID;
      IF NOT RecordRef2L.GET(RecordID2L) THEN EXIT;
        FilePathL := pgmWD.SetTargetDirectory(pgmWD.GetDocTypeParameterEntry('Table ' + FORMAT(TableIDL),1,0),varArrL);
        IF NOT (FILE.EXISTS(FilePathL + FORMAT(RecordRef2L.FIELD(5045182)))) THEN EXIT;
        pgmWD.DruckeReportArchivEingang(TableIDL,0,FORMAT(RecordRefL.FIELD(NumberL)),
          ReportIDL,pgmWD.GetDocTypeParameterEntry(ObjectTypeTextL + FORMAT(TableIDL),1,0));
    END;
END;

SLEEP(1000); // Eine Sekunde warten, da die PDF-Erstellung nur im Sekundentakt erfolgen kann!

RecordID2L := RecordRefL.RECORDID;
IF RecordRef2L.GET(RecordID2L) THEN BEGIN
  FieldRef2L := RecordRef2L.FIELD(5045180);
  FieldRef2L.VALUE := TRUE;
  RecordRef2L.MODIFY;
  FieldRef2L := RecordRef2L.FIELD(5045181);
  FieldRef2L.VALUE := CREATEDATETIME(TODAY,TIME);
  RecordRef2L.MODIFY;
END;

COMMIT;
SLEEP(2000);

In der Funktion wird neben dem Fortschrittsfenster auch die eigentliche Archivierung (pgmWD.DruckeReportArchivEingang) aufgerufen. Die Archivierung erstellt die PDF- und Index-Datei.

Re: fin.exe Memory nimmt zu

27. April 2009 11:30

Martinst könnte Recht haben mit seiner Aussage zu den Bitmaps!!!!!

Ich habe mal eine manuelle Eingrenzung gemacht und die Reports manuell mit Filter aufgerufen sowie als Drucker einen PDF-Writer angegeben.
Sind keine Bitmaps vorhanden, erhöht sich der Hauptspeicher nicht. Sind Bitmaps vorhanden erhöht sich der Hauptspeicher bei jedem Reportaufruf!
In der Archivierungs-Codeunit habe ich folgenden Code gefunden:

Code:
  DATABASE::"Sales Invoice Header":
    BEGIN
      CLEAR(SalesInvHeader);
      SalesInvHeader.SETRANGE("No.","No.");
      SalesInvHeader.FIND('-');
      RecRef.OPEN(112);
      RecRef.GETTABLE(SalesInvHeader);

      SetWDParameterforAction('Report '+FORMAT(ReportID),5,RecRef.RECORDID,0,'',FALSE);
      Archivieren(Profilname,dynvarArr);
      REPORT.RUNMODAL(ReportID,FALSE,FALSE,SalesInvHeader);
    END;


Wie soll ich hier nun aber den Clear durchführen, damit es keine Probleme mit den Bitmaps mehr gibt?
Merci, Beno

Re: fin.exe Memory nimmt zu

27. April 2009 11:30

Hallo,

du arbeitest mit Fieldref und RecordRef, das funktioniert nach meiner Erfahrung erst ab Client Version 4.0 SP3 mit sehr aktuellen Patches, ohne Absturz bei vielen Datensätzen.

Das Phänomen ist, das der Client immer langsamer wird, um dann irgendwann abzustürzen.

Gruß, fiddi

Re: fin.exe Memory nimmt zu

27. April 2009 11:53

Hast du vielleicht irgendwo einen Aufruf von einer oder mehrerer Funktionen des Report ohne den Report dann mit RUN/RUNMODAL aufzurufen?
Ich hatte vor Jahren mal das gleiche Verhalten wie du. Nachdem wir die Funktion aus dem Report in eine eigene Codeunit verlagert haben, war das Problem gelöst.

Re: fin.exe Memory nimmt zu

27. April 2009 11:54

Okay, könnte sein. Mein Problem ist aber der Zuwachs des zugeteilten Hauptspeichers. Und dies geschieht nur, bei Reports mit Bitmaps (wie Martinst schon sagte).
Meine offene Frage ist nur noch, wie ich diese Reports nun intialisiere oder cleare. Dann ist das Problem vielleicht gelöst.

Re: fin.exe Memory nimmt zu

27. April 2009 12:05

zu meinem vorhin gesagten, solltest du vielleicht RecRef auch Clearen, wenn du es nicht mehr benötigst.

Gruß, Fiddi

Re: fin.exe Memory nimmt zu

27. April 2009 17:05

Hallo Leute,

momentan bin ich ein wenig ratlos. Nach meiner Analyse, wird im Batchjob auch eine Automation erstellt und wieder gelöscht (CREATE/CLEAR).
Obwohl die Automation wieder gelöscht wird (CLEAR), benötigt sie bei jedem Aufruf knapp 300K. Die Reports, welche zum grossen Teil Bitmaps enthalten, benötigen jedesmal knapp 180K.
Der zugeteilte Hauptspeicher wird aber laufend um 400 - 500 K erhöht und nicht wieder freigegeben. Werden nun mehrere Tausend Reports gedruckt, wird es schon langsam knapp mit dem RAM.

Ich habe auch Tests mit dem PDF-Writer gemacht. Bei Reports ohne Bitmap erhöht sich der zugeteilte Hauptspeicher praktisch nicht. Mit Bitmaps erhöht er sich aber laufend und verringert sich nie mehr.
Auch die Variante mit Report-Variabeln und deren CLEAR hat nichts gebracht.

Es gibt also 2 Probleme:

Einerseits das Drucken von Reports mit Bitmpas und andererseits die Automations. Beides verbraucht RAM und wird nicht mehr zurückgegeben.

Habt ihr irgendeine Idee, wie ich dies vermeiden kann?

VIELEN DANK, BENO

Re: fin.exe Memory nimmt zu

27. April 2009 17:21

Hallo beno,

wenn die DB nicht so groß ist, versuche doch mal bei einer Kopie das ganze mit einem 5.0 SP1 Client zu fahren. Ich vermute, das dein Speicherproblem dann weg ist.

Gruß, Fiddi