Funktionsweise der internen Speicherverwaltung von Hochsprachen ?

29/11/2010 - 11:21 von Jaromir Prinzler | Report spam
Hallo !

Ich habe eine (natürlich mehrere) Funktion oder Methode (bei Objekten)
welche mir einen Speicherbereich
allokiert und mir den Adresszeiger darauf zurück gibt. Beispielsweise wenn
ich einen String zurecht trimme
(Leerzeichen entfernen) oder wenn ich eine Struktur anfordere.

Jetzt verwende ich ein Adressfeld mit endlicher Größe (32648 Zeiger) in
welchem diese temporàren
Speicherbereiche vermerkt werden. Diese werden automatisch beim Programmende
wieder frei gegeben.

Da die Anzahl der Adresszeiger aber endlich ist, werden irgendwann wieder
die ersten Speicherplàtze
benutzt da diese wohl (und hoffentlich) inzwischen nicht mehr innerhalb des
Programmes genutzt werden.

Soweit funktioniert es so auch, aber wie làuft es richtig?

Wenn ich in einer Programmiersprache z.B. Trim(char *) oder SubStr(char *)
nutze wird ja nicht der
Original Zeiger zurück gegeben, sondern ein interner mit dem entsprechend
geànderten Inhalt.

Wie kann ich oder der Compiler den nun heraus finden wann ein interner
Zeiger wirklich nicht mehr benötigt wird?

Sicherlich kann ich mittels malloc und free selbst arbeiten, aber dann wàren
verschachtelte Aufrufe wie...

char *pszOriginal = "Jaromir";
char *pszCopy = LeftStr(RightStr(pszOriginal, 5), 3);

printf("%s %s", pszOriginal, pszCopy);

ergibt

Jaromir rom

...nicht möglich, da ich den Rückgabewert von "RightStr" nicht kenne (kennen
will).

Habt Ihr eine Idee ? Danke für die Tipps!

Grüße aus Berlin

Jaro
 

Lesen sie die antworten

#1 Markus Wichmann
29/11/2010 - 14:38 | Warnen spam
Jaromir Prinzler schrieb:
Hallo !

Ich habe eine (natürlich mehrere) Funktion oder Methode (bei Objekten)
welche mir einen Speicherbereich
allokiert und mir den Adresszeiger darauf zurück gibt. Beispielsweise wenn
ich einen String zurecht trimme
(Leerzeichen entfernen) oder wenn ich eine Struktur anfordere.




OK. Aber Strings kann man auch trimmen, ohne sie zu duplizieren.

Jetzt verwende ich ein Adressfeld mit endlicher Größe (32648 Zeiger)
in welchem diese temporàren Speicherbereiche vermerkt werden. Diese
werden automatisch beim Programmende wieder frei gegeben.




Die Nummer klingt irgendwie krumm. Meintest du 2^15? Also 32768? Man
sollte davon ausgehen, dass bei modernen Betriebssystemen alles, was mit
malloc() geholt wurde, bei Programmende wieder freigegeben wird. Hier,
auf Linux, nutzt malloc nur eine von zwei Methoden, sich Speicher zu
besorgen: brk(), was lediglich das Datensegment vergrößert (ein Mapping,
das also am Programmende wieder gelöscht wird) und mmap(), was lediglich
ein Mapping anlegt, dass am Programmende wieder gelöscht wird.

Das malloc aus der dietlibc verwendet sogar nur mmap() (und kann
Speicher leaken, aber das gehört nicht hierher.)

Da die Anzahl der Adresszeiger aber endlich ist, werden irgendwann
wieder die ersten Speicherplàtze benutzt da diese wohl (und
hoffentlich) inzwischen nicht mehr innerhalb des Programmes genutzt
werden.


Soweit funktioniert es so auch, aber wie làuft es richtig?

Wenn ich in einer Programmiersprache z.B. Trim(char *) oder SubStr(char *)
nutze wird ja nicht der
Original Zeiger zurück gegeben, sondern ein interner mit dem entsprechend
geànderten Inhalt.

Wie kann ich oder der Compiler den nun heraus finden wann ein interner
Zeiger wirklich nicht mehr benötigt wird?

Sicherlich kann ich mittels malloc und free selbst arbeiten, aber dann wàren
verschachtelte Aufrufe wie...

char *pszOriginal = "Jaromir";
char *pszCopy = LeftStr(RightStr(pszOriginal, 5), 3);

printf("%s %s", pszOriginal, pszCopy);

ergibt

Jaromir rom

...nicht möglich, da ich den Rückgabewert von "RightStr" nicht kenne (kennen
will).

Habt Ihr eine Idee ? Danke für die Tipps!




Also, die einzige Funktion, die den Rückgabewert von RightStr() kennt,
ist ja LeftStr(). Infolgedessen wàre das einfachste, den Funktionen
einen Parameter hinzuzufügen, ob sie den übergebenen String danach
löschen sollen oder nicht. So in etwa:

char* LeftStr(char* in, size_t len, int free_after_use)
{
char* rv;
if (!in) return NULL;
rv = malloc(len + 1);
if (rv) {
strncpy(rv, in, len);
rv[len] = 0;
}
if (free_after_use) free(in);
return rv;
}

char* RightStr(char* in, size_t len, int free_after_use)
{
char* rv;
if (!in) return NULL;
rv = strdup(in + strlen(in) - len);
if (free_after_use) free(in);
return rv;
}

Hat jetzt nur noch das Problem, dass du, wenn deine Beispielzeile eine
NULL ergibt, nicht weißt, welche Funktion jetzt fehlschlug. Und dann
hast du vermutlich trotzdem ein Speicherleck.

Die Alternative besteht darin, C++ zu verwenden, wo du Speicherfreigaben
in den Destruktor packen kannst. Oder du benutzt einen Garbage Collector
(GIDF).

Oder du machst es so, wie C-Programmierer schon seit Jahrzehnten: Du
trennst Allokation und Verarbeitung voneinander, und làsst dir einen
Zeiger auf den Ausgabebereich nebst Größe desselben übergeben.

Grüße aus Berlin

Jaro






Tschö,
Markus

Ähnliche fragen