Frage

Wir haben eine D2007 Anwendung, deren Speicherbedarf wächst stetig, wenn sie auf Windows Server 2008 (x64, SP1) ausgeführt wird.
Es verhält sich normal auf Windows Server 2003 (x32 oder x64), XP, etc ... wo es rauf und runter geht wie erwartet.
Wir haben mit dem mitgelieferten Memory Manager oder die neuesten FastMM4 4.92 mit dem gleichen Ergebnis ausprobiert.

Hat jemand versucht, die Speichernutzung aller Delphi-App auf Win2008 zu überwachen und bestätigen würde?
Oder würde keine Ahnung haben?

Precisions:
- keine Speicherlecks im gesunden Menschenverstand (und ja ich sehr vertraut bin mit FastMM et al)
- Speicherverbrauch wurde mit Process Explorer überwacht; beide virtuellen Speicher (Private Bytes) und Physical Memory (WorkingSet Private) wachsen auf Win2008
- Speicherverbrauch immer noch wächst auch bei Speicherdruck war. (Das ist, wie wir gekommen ist, zu untersuchen, wie es einen Fehler verursacht hat, sondern nur auf Win2008-Box)

Aktualisieren :. Die // ** repaced ** // Code viel einfacher als unsere App ist aber zeigt das gleiche Verhalten
Erstellen einer Liste von 10 Millionen Objekte dann 10.000.000 Schnittstellen, ausgeführt 2mal wächst den verwendeten Speicher von ~ 60 MB und etwa mehr 300MB für 100 weitere Ausführungen auf Windows Server 2008, aber nur zurück, wo es war auf XP.
Wenn Sie mehrere Instanzen starten, wird der Speicher nicht den anderen Instanzen zu ermöglichen freigegeben auszuführen. Stattdessen wächst die Auslagerungsdatei und der Server kriecht ...

Update 2 : siehe QC melden 73347
Nach einer weiteren Untersuchung haben wir es verfolgt Kritische Abschnitte nach unten , wie in der unten stehenden Code dargestellt.
Setzen Sie diesen Code in eine einfache VCL-Anwendung mit einem Knopf. Und Monitor mit Process Explorer:
es beginnt bei ~ 2,6 MB und nach 5 Läufen (klickt auf die Schaltfläche) bleibt es bei ~ 118.6MB.
116MB verloren in fünf Ausführungen.

//***********************
const
  CS_NUMBER = 10000000;
type
  TCSArray = Array[1..CS_NUMBER] of TRTLCriticalSection;
  PCSArray = ^TCSArray;

procedure TestStatic;
var
  csArray: PCSArray;
  idx: Integer;
begin
  New(csArray);

  for idx := 1 to length(csArray^) do
    InitializeCriticalSection(csArray^[idx]);

  for idx := 1 to length(csArray^) do
      DeleteCriticalSection(csArray^[idx]);

  Dispose(csArray);
end;

procedure TestDynamic(const Number: Integer);
var
  csArray: array of TRTLCriticalSection;
  idx: Integer;
begin
  SetLength(csArray, Number);

  for idx := Low(csArray) to High(csArray) do
    InitializeCriticalSection(csArray[idx]);

  for idx := Low(csArray) to High(csArray) do
      DeleteCriticalSection(csArray[idx]);
end;

procedure TForm4.Button1Click(Sender: TObject);
begin
  ReportMemoryLeaksOnShutdown := True;
  TestStatic;
  TestDynamic(CS_NUMBER);
end;
War es hilfreich?

Lösung 2

Eigentlich hat Microsoft eine Änderung die Kritischen Abschnitte einige Debug-Informationen hinzuzufügen. Dieser Debug-Speicher wird nicht bis zum Ende der Anwendung freigegeben, aber irgendwie zwischengespeichert und wiederverwendet, weshalb nach einer Weile es Plateau kann.

Die Lösung, wenn Sie ohne das Gefühl, diese Erinnerung Strafe viel Kritische Abschnitte erstellen möchten ist die VCL-Code Patch zu ersetzen Anrufe InitializeCriticalSection durch Anrufe auf InitializeCriticalSectionEx und geben sie die Fahne CRITICAL_SECTION_NO_DEBUG_INFO die Schaffung der Debug-Struktur zu vermeiden.

Andere Tipps

Es gibt ein neues Sysinternals-Tool namens VMMap die die visualisiert zugewiesenen Speicher. Vielleicht könnte es Ihnen zeigen, was die großen Speicherblöcke sind.

Haben Sie umfassen FastMM mit voller Debug-Modus? Gerade ist die FastMM4 Einheit direkt in Ihrem Projekt und setzt

ReportMemoryLeaksOnShutdown := True

Wenn es nichts berichtet ist, vielleicht ist alles normal beim Beenden des Programms befreit (vielleicht wegen der Referenzzählung). Sie könnten verwenden AQTime Speicher in Echtzeit zu überwachen. Mit dieser Anwendung können Sie das Bytes sehen für jede Klasse Namen und für Rest des verwendeten Speichers „Zählen“. Vielleicht können Sie sehen, wer den Speicher verwendet. Die zeitlich begrenzte Demoversion ist genug für diesen Job.

Beziehen Sie sich auf den Private Bytes, virtuelle Größe oder dem Working Set? Führen Sie Process Explorer von Sysinternals den Speicher für eine bessere Idee zu überwachen von was los ist.

Ich habe keine spezielle Erfahrung mit diesem (obwohl ich laufe 2008 x64 SP1, so könnte es testen), aber ich werde vorschlagen, dass Sie eine Testanwendung erstellen, die eine Reihe von Speicher zuordnet und sie dann freizugeben. Führen Sie Process Explorer von Sysinternals den Speicher zu überwachen.

Wenn Sie testen Anwendung das gleiche Verhalten reproduziert dann versuchen, einigen Speicherdruck erzeugt durch den Speicher in einem anderen Prozess Zuteilung -. So sehr, dass es scheitern wird, es sei denn, dass zuvor freigegebene Speicher in dem ersten Prozess freigegeben wird

Wenn das weiterhin fehlschlägt, versuchen Sie einen anderen Speicher-Manager. Vielleicht ist es FastMM, dass es tut.

Überprüfen Sie, ob Sie dieses Problem (dies ist ein anderes Thema , in keinem Zusammenhang mit dem einem, die ich in den Kommentaren zu Ihrer Frage erwähnt habe).

habe ich diesen Code, um dieses Problem auf meinen Anwendungen zu korrigieren. Ist der gleiche Fall von FastCode, um das Update zu Lauf machen Sie müssen das Gerät als erstes Gerät Ihres Projekts zu stellen. Wie die uRedirecionamentos in diesem Fall: eingeben Bild Beschreibung hier

unit uCriticalSectionFix;
// By Rodrigo F. Rezino - rodrigofrezino@gmail.com

interface

uses
  Windows;

implementation

uses
  SyncObjs, SysUtils;

type
  InitializeCriticalSectionExProc = function(var lpCriticalSection: TRTLCriticalSection; dwSpinCount: DWORD; Flags: DWORD): BOOL; stdcall;

var
  IsNewerThenXP: Boolean;
  InitializeCriticalSectionEx: InitializeCriticalSectionExProc;

type
  PJump = ^TJump;
  TJump = packed record
    OpCode: Byte;
    Distance: Pointer;
  end;

  TCriticalSectionHack = class(TSynchroObject)
  protected
    FSection: TRTLCriticalSection;
  public
    constructor Create;
  end;

function GetMethodAddress(AStub: Pointer): Pointer;
const
  CALL_OPCODE = $E8;
begin
  if PBYTE(AStub)^ = CALL_OPCODE then
  begin
    Inc(Integer(AStub));
    Result := Pointer(Integer(AStub) + SizeOf(Pointer) + PInteger(AStub)^);
  end
  else
    Result := nil;
end;

procedure AddressPatch(const ASource, ADestination: Pointer);
const
  JMP_OPCODE = $E9;
  SIZE = SizeOf(TJump);
var
  NewJump: PJump;
  OldProtect: Cardinal;
begin
  if VirtualProtect(ASource, SIZE, PAGE_EXECUTE_READWRITE, OldProtect) then
  begin
    NewJump := PJump(ASource);
    NewJump.OpCode := JMP_OPCODE;
    NewJump.Distance := Pointer(Integer(ADestination) - Integer(ASource) - 5);

    FlushInstructionCache(GetCurrentProcess, ASource, SizeOf(TJump));
    VirtualProtect(ASource, SIZE, OldProtect, @OldProtect);
  end;
end;

procedure OldCriticalSectionMethod;
asm
  call TCriticalSection.Create;
end;

{ TCriticalSectionHack }

const
  CRITICAL_SECTION_NO_DEBUG_INFO = $01000000;
  NEW_THEN_XP = 6;

constructor TCriticalSectionHack.Create;
begin
  inherited Create;
  if IsNewerThenXP then
    InitializeCriticalSectionEx(FSection, 0, CRITICAL_SECTION_NO_DEBUG_INFO)
  else
    InitializeCriticalSection(FSection);
end;

procedure AdjustMethod;
var
  LKernel32: HModule;
begin
  if IsNewerThenXP then
  begin
    LKernel32 := LoadLibrary('kernel32.dll');
    @InitializeCriticalSectionEx := GetProcAddress(LKernel32, 'InitializeCriticalSectionEx');
  end;
end;

initialization
  AddressPatch(GetMethodAddress(@OldCriticalSectionMethod), @TCriticalSectionHack.Create);
  IsNewerThenXP := CheckWin32Version(NEW_THEN_XP, 0);
  AdjustMethod;


end.

Neben Alexander, in der Regel wird dies als "Heapfragmentierung" genannt.

Beachten Sie, dass FastMM sollte elastische und insgesamt schneller sein, aber wenn die ursprüngliche App für den D7 memmanager abgestimmt wurde, FastMM könnte tatsächlich schlechter durchführen.

Nun, kann die Speichernutzung sogar erhöhen, wenn es kein in der Anwendung Speicherverlust ist. In diesen Fällen besteht die Möglichkeit, als Sie Leck einer anderen Ressource haben. Zum Beispiel, wenn Ihr Code zuweist, sagen, ein Bitmap und obwohl gibt er alle Objekte, sondern schafft über Finalisierung einige HBITMAP zu vergessen.

FastMM wird Ihnen sagen, dass Sie keine Speicherleck in Ihrer Anwendung haben, da Sie alle Ihre Objekte und Daten befreit haben. Aber Sie leckt noch andere Arten von Ressourcen (in meinem Beispiel - GDI-Objekte). Undichte andere Arten von Ressourcen, um Ihr Gedächtnis beeinflussen kann.

Ich schlage vor, Sie ein anderes Werkzeug, um zu versuchen, die nicht nur Speicherlecks überprüft, aber auch andere Arten von Lecks zu. Ich denke, dass AQTime Lage ist, dies zu tun, aber ich bin nicht sicher.

Ein weiterer möglicher Grund für dieses Verhalten ist die Fragmentierung des Speichers. Angenommen Mave Sie 2000 Objekte von 1 Mb in der Größe zugewiesen (lassen Sie sich für eine Minute über MM Gemeinkosten und das Vorhandensein von anderen Objekten im User-Space vergessen). Jetzt haben Sie die volle 2 GB Speicher beschäftigt. Angenommen nun, dass Sie frei alle auch Objekte, so dass Sie nun „gestrippt“ Speicherplatz haben, wobei 1 Mb beschäftigt und freie Blöcke gemischt werden. Obwohl jetzt haben Sie tun 1 GB freien Speicher, aber Sie sind nicht in der Lage einen Speicher für jedes 2MB-Objekt zuzuordnen, da die maximale Größe des freien Blockes 1 Mb ist nur (aber Sie haben 1000 solche Blöcke haben;)). Wenn der Speicher-Manager Blöcke verwendet größer als 1 MB für Ihre Objekte, dann kann es nicht die Speicherblöcke zurück in OS loslassen, wenn Sie Ihre selbst Objekte befreit haben:

[ [busy] [free] [busy] [free] [busy] [free] ]
[ [busy] [free] [busy] [free] [busy] [free] ]...

Diese großen [...] Blöcke sind halb voll, so MM sie nicht zu O geben kann. Wenn Sie einen anderen Block fragen werden, die> 1 Mb dann MM benötigen noch einen weiteren Block von OS zuzuweisen:

[ [busy] [free] [busy] [free] [busy] [free] ]
[ [busy] [free] [busy] [free] [busy] [free] ]...
[ [your-new-object] [free.................] ]
Hinweis

, dass dies sind nur Beispiele für incresing Speichernutzung, wenn Sie nicht Speicherverlust haben. Ich sage nicht, dass Sie die genaue Situation haben: D

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top