AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Eine Variable "umziehen"

Ein Thema von LDericher · begonnen am 14. Okt 2009 · letzter Beitrag vom 15. Okt 2009
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von LDericher
LDericher

Registriert seit: 29. Jan 2007
Ort: Erkelenz
224 Beiträge
 
Delphi 7 Enterprise
 
#1

Eine Variable "umziehen"

  Alt 14. Okt 2009, 18:48
Hallo DP!

Ich stehe vor folgendem Problem:
Ich arbeite an einem Parser für eine schlanke, erweiterbare Scriptsprache, und bin dabei, das Funktions/Prozedursystem zu implementieren. Dazu will ich aus einer DLL Funktionen mit einem Array of Pointer als Parameter callen. Funktionierte in den Testläufen auch wuderbar, darum geht's nicht.

Nur, wenn ich mein Script parse, will ich gleich die Pointer auf die Parameter bekommen und einlagern in ein selbtgebautes "CodeItem". Das Problem ist, wenn ich nun einen PString zwischenspeichere und dann weiterparse, dann kommt vereinfacht (Durch Schleifen) so etwas heraus:
Delphi-Quellcode:
var
  AusgabeArray: array of Pointer;
  S: string;
begin
SetLength(AusgabeArray, 2);
S:='TestEins';
AusgabeArray[0]:=@Test;
S:='Blah';
AusgabeArray[1]:=@Test;
end;
Mir ist klar, was hier schiefläuft: Der Speicherbereich von S wird ja zwischendurch nicht verändert, und so kommt letzen Endes das allmächtige "Blah" an beiden Stellen des Arrays heraus...
Kann ich irgendwie dem String/Integer/Boolean/Float/... neuen Speicherbereich zuordnen, sodas ich wirklich zwei Pointer einsortiere?

MfG, Euer LDer
"Clicking this button you agree with our Verantwortungsverzicht und Abkommen."
Zitat von Ein unentschlossener Programmierer:
Enabled:=true or false or true or false or true or false;
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.152 Beiträge
 
Delphi 12 Athens
 
#2

Re: Eine Variable "umziehen"

  Alt 14. Okt 2009, 19:04
Delphi-Quellcode:
SetLength(AusgabeArray, 2);
S:='TestEins';
AusgabeArray[0]:=@Test;
S:='Blah';
AusgabeArray[1]:=@Test;
also hier kann aus zwei Gründen nicht draus werden
1.) AusgabeArray[0] und AusgabeArray[1] zeigen auf die selbe Variable und haben immer den selben Inhalt
2.) S ist eine lokale Variable und würde nach ablauf der Prozedur gelöscht, also damit auch der String

was geht, ist aber das:
ein String ist ja intern ein Zeiger und ließe sich daher leicht in einen Pointer,
Delphi-Quellcode:
SetLength(AusgabeArray, 2);
S:='TestEins';
AusgabeArray[0] := Pointer(Test); // bzw. := PChar(Test);
S:='Blah';
AusgabeArray[1] := Pointer(Test);
aber hier macht einem die Referenzzählung einen Strich durch die Rechnung, da sie durch soeinen Cast nicht verändert wird und demnach der String dann wiederum freigegeben wird

also muß man den Cast so anlegen, daß er die Referenzzählung beachtet und das ginge z.B. so
Delphi-Quellcode:
SetLength(AusgabeArray, 2);
S:='TestEins';
String(AusgabeArray[0]) := Test;
S:='Blah';
String(AusgabeArray[1]) := Test;
Delphi-Quellcode:
SetLength(AusgabeArray, 2);
String(AusgabeArray[0]) := 'TestEins';
String(AusgabeArray[1]) := 'Blah';
PS: irgendwan mußt du den String/Speicher auch wieder freigeben und das ginge dann so
String(AusgabeArray[1]) := '';

PS2: du hast dir aber auch einen Shared-MemoryManager besorgt?
denn du willst hier ja anscheinend Speicher über die Programmgrenzen hinweg verwalten/bearbeiten
und das geht nur im SELBEN speichermanager ... hier hat aber standardmäßig die EXE und die DLL jeder ihren eigenen Manager.

Es sei denn du verwendest einen WideString, welcher nicht über den Delphi-MemoryManager läuft, sondern über den vom OLE32-System.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von littleDave
littleDave

Registriert seit: 27. Apr 2006
Ort: München
556 Beiträge
 
Delphi 7 Professional
 
#3

Re: Eine Variable "umziehen"

  Alt 14. Okt 2009, 19:20
Zitat von himitsu:
PS2: du hast dir aber auch einen Shared-MemoryManager besorgt?
denn du willst hier ja anscheinend Speicher über die Programmgrenzen hinweg verwalten/bearbeiten
und das geht nur im SELBEN speichermanager ... hier hat aber standardmäßig die EXE und die DLL jeder ihren eigenen Manager.

Es sei denn du verwendest einen WideString, welcher nicht über den Delphi-MemoryManager läuft, sondern über den vom OLE32-System.
Man kann es auch anders machen - indem man in der DLL den Speichermanager der Hostanwendung benutzt. Das gleiche benutze ich bei meiner Script-Sprache bei den Packages auch. Im Enddefekt geht das ganz einfach:

in der DLL erstellt man so eine Funktion:
Delphi-Quellcode:
var
  oldMM : TMemoryManager;
  newMM : TMemoryManager;
  useMM : boolean;

procedure DLL_SetMemoryManager(const MemoryManager: TMemoryManager); stdcall;
begin
  if not useMM then
  begin
    // den bisherigen MemoryManager der DLL speichern
    GetMemoryManager(oldMM);
    // den neuen MemoryManager aktivieren
    newMM := MemoryManager;
    SetMemoryManager(newMM);
    // speichern, dass man den neuen MemoryManager benutzt
    useMM := True;
  end;
end;

procedure DLL_ResetMemoryManager; stdcall;
begin
  // falls ein fremder MemoryManager benutzt wurde
  if useMM then
  begin
    // den alten wieder zurücksetzen.
    SetMemoryManager(oldMM);
    useMM := False;
  end;
end;

exports
  DLL_SetMemoryManager,
  DLL_ResetMemoryManager;
Beim laden der DLL führt man dann so früh wie möglich in der Host-Anwendung die DLL-Funktion DLL_SetMemoryManager folgendermaßen aus:
Delphi-Quellcode:
var MemoryManager: TMemoryManager;
begin
  GetMemoryManager(MemoryManager);
  DLL_SetMemoryManager(MemoryManager);
end;
und beim Beenden bzw. beim Entladen der DLL ruft man einfach wieder die Funktion DLL_ResetMemoryManager der DLL auf.

Wichtig ist dabei: man sollte in der DLL kein Speicher vor dem DLL_SetMemoryManager anfordern. Zudem sollte jeder Speicher, der nach dem DLL_SetMemoryManager angefordert wurde, vor dem DLL_ResetMemoryManager wieder freigegeben werden.

Grüße
Jabber: littleDave@jabber.org
in case of 1 is 0 do external raise while in public class of object array else repeat until 1 is 0
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.152 Beiträge
 
Delphi 12 Athens
 
#4

Re: Eine Variable "umziehen"

  Alt 14. Okt 2009, 19:53
Wie man den SharedMM einrichtet ist ja egal, hauptsache man macht es, wenn man Speicher über die Grenzen hinweg verwalten will/muß.


Zitat von littleDave:
Wichtig ist dabei: man sollte in der DLL kein Speicher vor dem DLL_SetMemoryManager anfordern. Zudem sollte jeder Speicher, der nach dem DLL_SetMemoryManager angefordert wurde, vor dem DLL_ResetMemoryManager wieder freigegeben werden.
Und genau da liegt ein großes Problem bei deiner Variante.
Sobald du z.B. die Unit SysUtils in deinem Projekt hast, wird unweigerlich der DLL-Eigene Manager schon verwendet, noch bevor du deine DLL_SetMemoryManager aufrufen kannst.

Daher wurde z.B. bei ShareMem von Borland der Manager der DLL in der EXE verwendet, da es sehr leicht möglich ist den Manager in dieser Richtung zu übergeben.

Darum ist auch mal dieser Code entstanden.
Und glaub mir, der ist schon vereinfacht ... also ich vor knapp 2 Jahren mit sowas anfing, da war der Code noch "kompliziert".
http://www.delphipraxis.net/internal...t.php?t=159601

Der Einfachste Weg ist immernoch Borlands ShareMem (borlndmm.dll)
oder man nutzt die Möglichkeiten von FastMM aus, denn dieses läßt sich auch als Shared-MM konfigurieren.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von littleDave
littleDave

Registriert seit: 27. Apr 2006
Ort: München
556 Beiträge
 
Delphi 7 Professional
 
#5

Re: Eine Variable "umziehen"

  Alt 14. Okt 2009, 19:59
Zitat von himitsu:
Zitat von littleDave:
Wichtig ist dabei: man sollte in der DLL kein Speicher vor dem DLL_SetMemoryManager anfordern. Zudem sollte jeder Speicher, der nach dem DLL_SetMemoryManager angefordert wurde, vor dem DLL_ResetMemoryManager wieder freigegeben werden.
Und genau da liegt ein großes Problem bei deiner Variante.
Sobald du z.B. die Unit SysUtils in deinem Projekt hast, wird unweigerlich der DLL-Eigene Manager schon verwendet, noch bevor du deine DLL_SetMemoryManager aufrufen kannst.
So schlimm ist es nicht, da man vor dem finalization der DLL (also auch da, wo der Speicher der SysUtils wieder freigegeben wird), die Funktion DLL_ResetMemoryManager aufruft und somit den MemoryManager vom Anfang wieder als aktiv setzt.
Jabber: littleDave@jabber.org
in case of 1 is 0 do external raise while in public class of object array else repeat until 1 is 0
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.152 Beiträge
 
Delphi 12 Athens
 
#6

Re: Eine Variable "umziehen"

  Alt 14. Okt 2009, 20:12
Zitat von littleDave:
So schlimm ist es nicht, da man vor dem finalization der DLL (also auch da, wo der Speicher der SysUtils wieder freigegeben wird), die Funktion DLL_ResetMemoryManager aufruft und somit den MemoryManager vom Anfang wieder als aktiv setzt.
Da würde ich an deiner Stelle nicht so einfach und blind drauf vertauen.

z.B. rufe mal die Funktion Delphi-Referenz durchsuchenLanguages aus der Unit SysUtils auf.
Diese nutzt intern ein Objekt, welches nicht schon in der Initialisierung der Unit erstellt wird, sondern erst beim ersten Aufruf der Funktion, allerdings wird dieses Objekt erst in der Finalisierung der Unit freigegeben
und da hast du dem Objekt schon seinen Speichermanager gemopst, in welchem es erstellt wurde.

Und da gibt es noch mehrere Stellen, wo soetwas passiert.
z.B. Application der Unit Forms ist da auch ein netter Fall
und dann gibt es noch mehr in Classes, Graphics und vorallem die Indy's sind da nette Gegenspieler
usw.


Also wenn man da in seinem eigenem Programm die Kontrolle darüber behält, was wo und vorallem wann erstellt/freigegeben wird, dann kann man es sich schon einfach machen,

Aber wenn du z.B. sowas wie deine Script-Sprache auch mal an andere Programmierer weitergeben willst, wo du absolut keinen Einfluß auf das Speicherverhalten hast, dann sollte man schon etwas aufpassen.


[add]
PS: Aus diesen Gründen wird bei meiner Version auch (1.) die DLL dynamisch geladen, damit sich der Speichermanager der EXE noch vor dem der DLL initialisieren kann.
Und (2.) der Manager innerhalb der DLL wird noch vor "allen" anderen Units innerhalb der DLL gestartet/übernommen, also noch von der Initialisierung von z.B. SysUtils und nach derern Finalisierung wird der MM auch erst wieder an das System (die EXE) zurückgegeben.

Und das 2. Verhalten ist auch bei allen Shared-MemoryManagern gleich.
1. ist bei mir nur umgekehrt, da ich ja den MM von der EXE auf die DLL übertragen möchte.
Möchte man den MM von der DLL in der EXE nutzen, so wie es sonst alle anderen Shared-MMs machen, dann muß die DLL statisch vor der EXE geladen werden.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von LDericher
LDericher

Registriert seit: 29. Jan 2007
Ort: Erkelenz
224 Beiträge
 
Delphi 7 Enterprise
 
#7

Re: Eine Variable "umziehen"

  Alt 15. Okt 2009, 12:08
Tag,

Hab jetzt einfach die Methode von littledave reingenommen, da ich meine DLLs auch dynamisch lade. Bis jetzt sieht's gut aus, und himitsu hat mir auch sehr geholfen

Also: und erledigt!

Bei weiteren Fragen/Problemen reaktiviere ich das Topic mal

Gruß,
LDer.
"Clicking this button you agree with our Verantwortungsverzicht und Abkommen."
Zitat von Ein unentschlossener Programmierer:
Enabled:=true or false or true or false or true or false;
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.152 Beiträge
 
Delphi 12 Athens
 
#8

Re: Eine Variable "umziehen"

  Alt 15. Okt 2009, 12:53
Hier mal ein winziges Beispiel, mit littleDaves Code:

Also die Exceptions sprechen doch für sich?
Es wird da dem Languages-Objekt und einem String einfach so der Manager unterm Arsch weggemopst.

PS: wegen dem IntToStr nicht wundern, aber dieses stellt ganz einfach nur eine "echte" Stringvariable bereit ... String-Konstanten sind ja nicht im MM abgelegt.
Angehängte Dateien
Dateityp: 7z mm_114.7z (45,0 KB, 9x aufgerufen)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von LDericher
LDericher

Registriert seit: 29. Jan 2007
Ort: Erkelenz
224 Beiträge
 
Delphi 7 Enterprise
 
#9

Re: Eine Variable "umziehen"

  Alt 15. Okt 2009, 14:27
Okay, ich verstehe das Problem, aber für mich dürfte es hier nicht relevant sein, da ich nur mit Parametern abeite, bzw. den dazugehörenden Prozeduren
Gut, ich speichere halt den MM zwischen, aber ich hatte noch keine solche Exceptions. Auch im Initialization/Finalization-Teil mache ich nix, genauso wenig wie zwischen Begin und End der DLL.
"Clicking this button you agree with our Verantwortungsverzicht und Abkommen."
Zitat von Ein unentschlossener Programmierer:
Enabled:=true or false or true or false or true or false;
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.152 Beiträge
 
Delphi 12 Athens
 
#10

Re: Eine Variable "umziehen"

  Alt 15. Okt 2009, 14:53
Zitat von LDericher:
da ich nur mit Parametern abeite, bzw. den dazugehörenden Prozeduren
Du nutzt also keinerlei Funktionen/Prozeduren, welche dir Delphi zur Verfügung stellt?
Also das nenne ich mal richtiges Non(V)CL

Zitat von LDericher:
Auch im Initialization/Finalization-Teil mache ich nix, genauso wenig wie zwischen Begin und End der DLL.
Och, wenn's nur darum geht ... die kann man auch weglassen (siehe Anhang)

Ich dachte nur je mehr Exceptions, desto besser.

Es geht ja nicht nur darum, daß du da nichts machst, denn da könnte man eingreifen und dieses selber rechtzeitig behandeln.
Aber es gibt genügend andere Units (im angehängten Beispiel ist es die böse SysUtils)


Nja, wie gesagt, wenn man schon fremden Code (und dazu gehört auch Delphi CL und VCL) nutzt, dann sollte man schon ein bissl aufpassen ... aber mann kann auch Glück haben und zufällig nur Funktionen erwischen, wo dennoch alles gut geht


PS: bei eigenen Programmen ist es ja nicht so schlimm, wenn nur diese abstürzen,
dann ist ja nur das eigene Programm betroffen und eventuell reagieren nur die eigenen Kunden sauer.
Aber stell dir mal vor du baust eine Komponente, welche andere in ihrem Programm verwenden ... diese bringt dann abundzu mal in fremden Anwendungen Probleme ... Wenn das Problem dann wissentlich eingebaut war, dann könnte das eine schöne Klagewelle erzeugen
Angehängte Dateien
Dateityp: 7z mm_ohne_160.7z (44,7 KB, 5x aufgerufen)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:50 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz