Delphi-PRAXiS

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)

Dennis07 27. Mär 2020 13:59

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

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

Naja, das kommt darauf an, wie man object hier interpretiert.
Wenn damit Objekttypen, also
Delphi-Quellcode:
TChild = object(TAncestor)
gemeint sind, dann hast du recht. Allerdings sind ja zunächst einmal
Delphi-Quellcode:
record
bzw.
Delphi-Quellcode:
class
-Instanzen auch Objekte ( -> "Instanzen eines vordefinierten Typs").

Stevie 27. Mär 2020 14:22

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

Zitat von himitsu (Beitrag 1460545)
Weil der String automatisch initialisiert wird und ein Boolean ohne vorherrige Zuweisung sonst einen Zufallswert haben kann.

Korrekt

Zitat:

Zitat von freimatz (Beitrag 1460549)
Bei einem Nullable<Boolean> braucht man dann statt einem Byte dann 9.

Ein Nullable<Boolean> ist auf 32bit 8 Byte groß (wegen dem Alignment). Habe schonmal packed in Betracht gezogen, aber der Speicherverbrauch von Nullables ist mir bisher nicht als triftiges Problem berichtet worden.

Zitat:

Zitat von dummzeuch (Beitrag 1460559)
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.

Eine string Referenz hat dieselbe Größe wie die eines interfaces (SizeOf(Pointer)) und es ist einfacher, einen Stringwert als "nicht null" Wert zuzuweisen, als mit der handcrafted IMT - zudem kann man das schöner im Debugger anschauen. Hat auch Hallvard Vassbotn in den Kommentaren vorgeschlagen.

Sollt es nachweislich einen Memoryleak durch diese Implementierung geben, dann bitte einen Bugreport mit komplettem Code zum nachstellen erstellen.

freimatz 28. Mär 2020 12:58

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

Zitat von Dennis07 (Beitrag 1460590)
Werden Felder nicht automatisch initialisiert?
Mir war doch so, und die OH sagt sazu:
Object instance data (fields) are also initialized to 0.
...

Zitat:

Zitat von Dennis07 (Beitrag 1460626)
Zitat:

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

Naja, das kommt darauf an, wie man object hier interpretiert.
Wenn damit Objekttypen, also
Delphi-Quellcode:
TChild = object(TAncestor)
gemeint sind, dann hast du recht. Allerdings sind ja zunächst einmal
Delphi-Quellcode:
record
bzw.
Delphi-Quellcode:
class
-Instanzen auch Objekte ( -> "Instanzen eines vordefinierten Typs").

Nein es kommt nicht drauf an wie "man" es definiert sondern wie es EMB definiert. Und das ist IMHO eindeutig.

@Stevie: bis jetzt habe ich noch nicht die Implementierung in Verdacht.

Dennis07 29. Mär 2020 04:15

AW: Spring4D Nullable<T> fHasValue: string;
 
Ja ne, dürfte ja klar sein, dass ich das so gemeint habe.
In wie fern ist das jetzt bitte "eindeutig", ob es sich um
Delphi-Quellcode:
object
oder einfach Objekte handelt? Geht hier aus dem Kontext keineswegs hervor. Klar kann man sagen "isso", aber das ist ja dann nicht eindeutig.
Was beispielsweise ist dann mit Klassen? Verhalten die sich wie Records oder wie Objects? (Antwort weiß ich zwar, bleibt aber ungeklärt, wenn man den Satz so deutet).
Also ganz klar ein Problem der schwammigen Formulierung des Satzes.

freimatz 30. Mär 2020 13:32

AW: Spring4D Nullable<T> fHasValue: string;
 
Du verwirrst mich. Jetzt versteh ich es selber nicht mehr. Vorher dachte ich wenigstens ich hättes verstanden. :-D
Die Seite mit "Object instance data (fields) are also initialized to 0" habe ich nochmals genauer gelesen. Da geht es doch nur um "initialize a global variable". Darum ging es mir mit den Nullable<T> nicht. Die werden in dem Projekt alle als member von Klassen, also Nachfahren von TObject, verwendet.

himitsu 30. Mär 2020 15:46

AW: Spring4D Nullable<T> fHasValue: string;
 
Globale Variablen, und Felder in Objekten, werden mit 0 initiliaisiert. (bei Globalen kann man auch optional einen anderen Wert vorgeben)
Lokale Variablen in Funktionen werden nicht initialisiert (mit Ausnahme ein paar weniger Typen, wie z.B. der String)

Beim Result von Funktionen mal so und mal so (je nach Typ), aber eigentlich auch nie so, wie man es braucht, also sind praktisch nie sicher "richtig" initialisiert (auch nicht für String und Co.).


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:58 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