Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Spring4D Nullable<T> fHasValue: string; (https://www.delphipraxis.net/203800-spring4d-nullable-t-fhasvalue-string%3B.html)

freimatz 26. Mär 2020 07:20

Spring4D Nullable<T> fHasValue: string;
 
Bei meiner Suche nach Memory-Leaks bin ich in unit "Spring.pas" auf diesen Code gestossen:
Delphi-Quellcode:
  Nullable<T> = record
  private
    fValue: T;
    fHasValue: string;
  ..
Kann mir jemand erklären warum man hier für fHasValue einen string nimmt und nicht ein Boolean? Zugewiesen wird dem string nur 'True' und ''.

himitsu 26. Mär 2020 07:48

AW: Spring4D Nullable<T> fHasValue: string;
 
Weil der String automatisch initialisiert wird und ein Boolean ohne vorherrige Zuweisung sonst einen Zufallswert haben kann.
(würde ich mir vorstellen, da ich bei meinen eigenen Komponenten leider auch so einen "Scheiß" bauen muß, da Embarcadero meine Vorschläge nötige Funktionalitäten mit wenigen Zeilen Qellcode nachzurüsten, einfach ignriert hat, obwohl ich denen sogar schon den fertigen Code geliefert hatte)

freimatz 26. Mär 2020 09:03

AW: Spring4D Nullable<T> fHasValue: string;
 
Ah ja Danke. Das ist eine plausible Erklärung.

Leider benötigt dieser string ja nicht gerade wenig Speicher (min 2x4=8 bei 32-Bit). Bei einem Nullable<Boolean> braucht man dann statt einem Byte dann 9.

Und leider bleibt beim Memory-Leak das ich untersuche immer dieser String übrig. Ich muss das noch genauer untersuchen, ich meine eine Exception ist beteiligt.

himitsu 26. Mär 2020 10:04

AW: Spring4D Nullable<T> fHasValue: string;
 
Ja, mit ein paar kleinen Änderungen im Delphi würde der Typ dann für NullableBoolean nur 2 Byte benötigen. (oder gar 1 Byte, wenn man z.B. nur 1 bzw. -1 für True annimmt, bzw. wenn nur das erste Bit werthaltig ist)
Falls du sicherstellen kannst, dass der die Variable immer initialisiert wird, könntest du den Typen entsprechend anpassen.

Oder ein Treestate-Boolean nutzen, aber dann mußt du "true" wirklich mit = True prüfen.
Delphi-Quellcode:
const NullBool = Boolean($55);

B := NullBool;
if not B then FALSCH
if B = False then FALSCH;
if B = True then WAHR;
if B = NullBool then LEER;
if B then WAHR_oder_LEER;
Wobei du hier den Speicher selbst initialisieren mußt, da automatische Initialisierungen immer nur 0 verwenden, was natürlich False wäre.

In einem Record, mit paar Implizit-Casts könne man hier noch False und Null im Record umdrehen, bzw. drinnen einen ENUM (Null,True,False) benutzen.

Ein MemoryLeak sollte aber beim Nullable<T> nicht bleiben.
Wo/wie benutzt du denn diesen Typen?




Wenn man das NULL im Datentypen selbst speichern könnte, bzw. wenn es möglich ist dort einen Wert im Wertebereich als NULL zu definieren,
dann ändert sich am eigentlichen Speicherverbrauch natürlich nichts.
Aber für soeinen generischen Typen, der alles aufnehmen kann, ist sowas natürlich garnicht oder nicht "einfach" umzusetzen.

Siehe dazu die Fließkommatypen (natürlich abgesehn von Currency) ansieht, dann sind da ein paar Bitkombinationen frei, die für sowas wie NAN, Inf und NegInf verwendet werden konnten.

Der schöne Günther 26. Mär 2020 11:49

AW: Spring4D Nullable<T> fHasValue: string;
 
Zitat:

Zitat von freimatz (Beitrag 1460549)
Leider benötigt dieser string ja nicht gerade wenig Speicher

Es muss ein gemanagter Typ sein, und die sind halt mindestens so groß wie ein Zeiger. 🤷

dummzeuch 26. Mär 2020 13:03

AW: Spring4D Nullable<T> fHasValue: string;
 
Zitat:

Zitat von freimatz (Beitrag 1460549)
Ah ja Danke. Das ist eine plausible Erklärung.

Leider benötigt dieser string ja nicht gerade wenig Speicher (min 2x4=8 bei 32-Bit). Bei einem Nullable<Boolean> braucht man dann statt einem Byte dann 9.

Und leider bleibt beim Memory-Leak das ich untersuche immer dieser String übrig. Ich muss das noch genauer untersuchen, ich meine eine Exception ist beteiligt.

Man könnte das nach einer Idee von Allen Bauer mit einem Interface auf 4 Bytes reduzieren. Keine Ahnung, warum Stefan das nicht gemacht hat.

Ich habe das für meine TNullableXxxx-Typen so implementiert und es funktioniert problemlos.

Edit:
Wobei: Eigentlich braucht der String auch nur 4 Bytes (oder 8 Bytes bei 64 Bit), wenn man immer denselben zuweist, denn dann ist das nur noch der Pointer auf den String-Descriptor. Der String selbst (und sein Descriptor) existiert nur noch ein einziges Mal. Ohne die Implementation in Spring4G zu gesehen zu haben, könnte ich mir vorstellen, dass das dort genauso implementiert ist.

himitsu 26. Mär 2020 13:59

AW: Spring4D Nullable<T> fHasValue: string;
 
Gut, wenn das Interface hier nur als Boolean (False=leer und True=einWert) verwendet wird, dann ist der String einfacher, denn wenn als String nur eine Konstante verwendet wird, dann braucht der auch keinen Speicher und man muß sich das DummyInterface nicht basteln

Dennis07 27. Mär 2020 01:09

AW: Spring4D Nullable<T> fHasValue: string;
 
Werden Felder nicht automatisch initialisiert?
Mir war doch so, und die OH sagt sazu:
Object instance data (fields) are also initialized to 0.

Trifft ja der Beschreibung nach auch so auf FHasValue zu. Habe ehrlich gesagt auch noch nie gehört oder gesehen, dass das nicht der Fall sein soll (abgesehen von lokalen Variablen bei Unterfunktionen, aber da funktioniert die Initialisierung ja eh scheinbar nie richtig).

freimatz 27. Mär 2020 07:25

AW: Spring4D Nullable<T> fHasValue: string;
 
Es ist aber kein "object" sondern ein record

Zitat:

Zitat von himitsu (Beitrag 1460551)
Ein MemoryLeak sollte aber beim Nullable<T> nicht bleiben.
Wo/wie benutzt du denn diesen Typen?

Ich selber eigentlich (noch) gar nicht. Die Verwendung ist im code schon drin und ich bin halt bei der Suche nach Leaks darübergestolpert.

Am Besten wäre EMB, würde das native unterstützen.

himitsu 27. Mär 2020 11:42

AW: Spring4D Nullable<T> fHasValue: string;
 
Zitat:

Zitat von freimatz (Beitrag 1460599)
Es ist aber kein "object" sondern ein record

Jupp, und da kommt es drauf an, wo diese Variable liegt.

Global oder als Feld in einem Objekt, wo der Speicher initialisiert wird,
oder als lokale Variable in einer Funktion/Prodedur/Methode, wo das eben nicht passiert.

Wobei Strings, dynamische Arrays und Interfaces "immer" initialisiert werden. (außer wenn in Pointern, wo jemand alles falsch macht und die Speicherverwaltung verhunzt hat)

automatisch freigegeben wird der String auch immer automatisch. (weswegen er auch vorher initialisiert werden musste, damit die Automatik funktioniert)


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:48 Uhr.
Seite 1 von 2  1 2      

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