os x stehen geblieben

  • Original von hns
    Und ob die Seiten zusammenhängend im Speicher liegen spielt keine Rolle. Das kann ja die MMU umsortieren.

    Wenn der Kernel das beherrscht funktioniert das auch. Tut er's?

    Und noch eine Limitierung: Dur hast 32bit für Adressen, also 4GByte Adressraum. Der ist nicht vollständig verfgbar, sondern nur ca. 2GB.


    Das ist nicht richtig. Du kannst 3,5GB Adreßraum für Deine Applikation nutzen, davon ist ein Block maximal 2GB groß der andere 1,5GB. 0,5GB sind für den Programmcode, Symbole etc. reserviert. Ich habe das schon ausprobiert, inklusive Speicher beschreiben, es geht wirklich.

    Einfach vergessen, da habe ich die OS verdreht, trotzdem kann man maximal einen 2GB Block allozieren, in plain C geht's jedenfalls. Dann ist es jedenfalls ein Problem des Arbeitsspeichers und dürfte sich einfach lösen lassen.
  • Die Größe, die man Collections mitteilt, hat damit gar nichts zu tun.

    a) Die Collection speichert Zeiger, nicht Objekte.
    b) Die Größe ist nur ein Hint.

    Du überschreibst einfach +alloc oder -init und gibst jeweils einen Zeiger auf deinem Block zurück, anstelle des Zeigers aus dem Heap. Wo liegt das Problem?

    Die Größe erhältst du mittels sizeof( Klasse ).
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von Tom9811
    Du überschreibst einfach +alloc oder -init und gibst jeweils einen Zeiger auf deinem Block zurück

    Habt Ihr Euch schon mal +allocWithZone und NSZone angeschaut? Das ist zwar seit Jahrzehnten nicht mehr wirklich notwendig (es war eine Speicheroptimierung von NextSTEP damit es mit glaube ich 8MByte RAM läuft), aber immer noch vorhanden.

    -- hns
  • Das kommt davon, wenn man NSArray als Test nimmt, da kommt 4 raus und das erinniert mich im 32Bit Modus fatal an Zeiger.

    Was mich aber verwundet, wenn ich folgendes Programm laufen lasse.

    C-Quellcode

    1. #include <stdlib.h>
    2. #include <stdio.h>
    3. #include <stdint.h>
    4. #include <string.h>
    5. #include <unistd.h>
    6. #include <sys/types.h>
    7. #include <sys/time.h>
    8. #include <sys/resource.h>
    9. static const size_t BLOCK_SIZE = 4096;
    10. static const size_t MAX_CHUNK = 2147483648;
    11. #define ANZAHL 550000
    12. struct block {
    13. char string[4096];
    14. };
    15. int main () {
    16. static void* liste[550000];
    17. struct rlimit rlp;
    18. printf ("pagesize ist %li\n", sysconf(_SC_PAGE_SIZE));
    19. getrlimit (RLIMIT_DATA, &rlp);
    20. printf ("max data block %li\n", rlp.rlim_max);
    21. getrlimit (RLIMIT_RSS, &rlp);
    22. printf ("max memory %li\n", rlp.rlim_max);
    23. getrlimit (RLIMIT_STACK, &rlp);
    24. printf ("max stack size %li\n", rlp.rlim_max);
    25. char* p = malloc (MAX_CHUNK);
    26. if (0 != p) {
    27. printf("Allokation von 2GB Block erfolgreich\n");
    28. memset(p, 0xFF, MAX_CHUNK);
    29. free(p);
    30. printf("2GB Block wieder freigegeben\n");
    31. } else {
    32. printf("Allokation von 2GB block fehlgeschlagen\n");
    33. }
    34. for (size_t i = 0; i !=ANZAHL; ++i) {
    35. liste[i] = malloc(BLOCK_SIZE);
    36. if (0 == liste[i]) {
    37. printf ("Kann den %li. Block nicht mehr allozieren\n", i+1);
    38. return(EXIT_FAILURE);
    39. }
    40. memset(liste[i], 0xFF, BLOCK_SIZE);
    41. }
    42. for (size_t i = 0; i != ANZAHL; ++i) {
    43. free(liste[i]);
    44. }
    45. return EXIT_SUCCESS;
    46. }
    Alles anzeigen


    Dann kann man 2GB allozieren und benutzen, ohne daß es Problem gibt. Allerdings wenn man einzelne Blöck von 4k allozieren will, dann scheitert es am Block 450.558 was ca. 1,7GB entspricht. Was passiert mit dem restlichen Speicher? Die einzige sinnvolle Erklärung für mich ist es, daß malloc das im Userspace verwaltet und so ziemlich viel vom Adreßraum aufbraucht. Anders ergibt das für mich keinen Sinn. Allerdings 300MB für eine popelige Liste von 450.000 Speicherblöcken? Das ist schon arg heftig.

    Wenn man zusätzlich statischen Speicher belegt, dann wird der Block von 2GB nicht angefaßt solange man unter 256MB statischen Speicher bleibt, wird er größer, wird der Heap eingeschränkt. Allerdings liefert getrlimit dann keinen korrekten Wert mehr zurück. Die Shell gibt den Wert auch nicht vor.
  • Original von Tom9811
    Die Größe, die man Collections mitteilt, hat damit gar nichts zu tun.
    ...
    b) Die Größe ist nur ein Hint.

    Es optimiert die Speicherallokation. Jedes malloc insbesondere im Multithreaded Prozessen kostet Zeit und die reallocs erspart man sich auch, wenn man Collections vorher mitteilt wie viele Daten man reinschreibt. Der Speicherfragmentation beugt man auch vor. Es ist daher sinnvoll es zu tun, wenn man viele Datensätze ablegen will, notwendig ist es nicht.
  • Ja, das weiß ich selbst. Wenn es darum gegangen wäre, hättte ich es auch geschrieben.

    Nur hat das nichts mit den von dir geäußerten Zweifeln zum Placement new zu tun. Dazu hatte ich geschrieben. Und hier gilt: Mit Placement new hat das soviel zu tun wie ein ein Waschkkorb voller Damenunterwäsche.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von Tom9811
    Wo liegt das Problem?

    Das Problem liegt darin, daß es mir nicht klar ist, wie ich einer Collection vermitle, wie sie bitte den Speicher für von ihre verwaltete Objekte verwalten soll. Ich sehe in der Doku keine Callbacks, Handles, etc. die mir so etwas auf die einfache Tour erlauben würden.

    Wie bringe ich eine Collection dazu, für die interne Struktur (Key-Objektzeiger und Value-Objektzeiger müssen in einer dynamischen Struktur verwaltet werden), die Key-Objekte und die Value-Objekte vorher allozierte Speicherblöcke zu benutzen. Simple Frage wie macht man das?
  • Jedesmal, wenn Du in Cocoa eine alloc Meldung verschickst, dann wird ein Speicherblock angefordert. Dasselbe passiert auch, wenn das eine Collection macht. Es scheint so zu sein, daß die Verwaltung dieser Blöcke nicht unerheblich Speicher verbraucht und daher schon vorher als vor Erreichen der 2GB Mark der Arbeitsspeicher zu neige geht. Du mußt Dir darüber Gedanken machen, wie Du mit weniger Arbeitsspeicher zu recht kommst. Probeweise kannst Du Deiner Applikation weniger virtuellen Adreßraum zu weisen (das hat den Vorteil das Programm braucht nicht so viel RAM), so daß Du in der Lage bist Dein Programm auf Situationen anzupassen, in denen der Arbeitsspeicher knapp wird. Siehe Doku zum Shell Befehle ulimit bzw. die man pages zu den Funktionen getrlimit bzw. setrlimit.
  • Üblicherweise werden in Framework nicht bei jeder Speicheranforderung an das Framework auch gleich Speicheranforderungen an das System geschickt. Wie es Cocoa macht, weiß ich nicht. Der Hintergrund ist, dass so der Speicher fragmentiert und außerdem der System-Overhead am Speicher schnell größer wird als der allozierte Speicher selbst.

    Er muss isch das einfach mal bei Cocoa anschauen und ggefls. selbst größere Speicherblöcke anfordern, die er dann benutzt.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Ich kann dir nicht folgen:
    Ob Objective-C so etwas kann, weiß ich nicht, aber ich habe so meine Zweifel.

    Ok, die Doku sagt, man kann NSMutableDictionary die Speichergröße vorher mitteilen.

    Wo ist der Zusammenhang zu std:vector?
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von tjp
    Jedesmal, wenn Du in Cocoa eine alloc Meldung verschickst, dann wird ein Speicherblock angefordert. Dasselbe passiert auch, wenn das eine Collection macht. Es scheint so zu sein, daß die Verwaltung dieser Blöcke nicht unerheblich Speicher verbraucht und daher schon vorher als vor Erreichen der 2GB Mark der Arbeitsspeicher zu neige geht. Du mußt Dir darüber Gedanken machen, wie Du mit weniger Arbeitsspeicher zu recht kommst. Probeweise kannst Du Deiner Applikation weniger virtuellen Adreßraum zu weisen (das hat den Vorteil das Programm braucht nicht so viel RAM), so daß Du in der Lage bist Dein Programm auf Situationen anzupassen, in denen der Arbeitsspeicher knapp wird. Siehe Doku zum Shell Befehle ulimit bzw. die man pages zu den Funktionen getrlimit bzw. setrlimit.


    ok, danke! und ein möglicher ansatz wäre evtl meine Objekte im worker thread speicher aus einer NSZone zu verwenden und dann die NSZone zum main thread zu pushen?

    gruss
    j.
    malloc: *** vm_allocate(size=1665622016) failed (error code=3)
  • Original von Tom9811
    Die Größe erhältst du mittels sizeof( Klasse ).


    sizeof() liefert bei mir wenn ich es auf ein dict oder ein array anwende leider immer 4 zurueck.
    also

    Quellcode

    1. NSLog(@"%i",sizeof(aDict));
    .

    was mache ich da falsch?
    malloc: *** vm_allocate(size=1665622016) failed (error code=3)
  • Dass da immer 4 zurückgegeben wird liegt einfach daran, dass das alles Pointer sind und ein Pointer hat auf 32-Bit Macs nunmal 4 Byte (= 32 Bit).
    "We can make all our dreams come true, but first we have to decide to awaken from them.", Josephine Baker
  • Original von Neum
    Dass da immer 4 zurückgegeben wird liegt einfach daran, dass das alles Pointer sind und ein Pointer hat auf 32-Bit Macs nunmal 4 Byte (= 32 Bit).


    hmm wie kann ich dann einfach rausfinden wieviel bytes ein array verbraucht? nur mit den performance tools ?
    malloc: *** vm_allocate(size=1665622016) failed (error code=3)
  • Es verbraucht in der Regel vier Bytes. Allerdings wird am Array eine weitere Struktur mit Kacheln hängen. Schau dir das mal in den Step-Sourcen an.

    Aber es ist die Frage, ob du das überhaupt so machen willst. Ich mutmaße, dass nicht der gesamte Speicehrverbrauch das Problem ist, sondern die Anzahl der Allozierungen. Grob erinnere ich mich da auch an was im Singh.

    Hier kann man daran denken, dass du dir selbst einen Pool baust, aus dem du den Speicher holst. Dazu musst du an +alloc ran. Und selbst dann ist es viel Arbeit, weil du ja nicht der einzige bist, der Speicher holt.

    Ich würde mich daher erst einmal der Sache wirklich genau auf den Grund gehen.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Collections speichern keine Objekte. Daher wird es da auch nichts geben.

    Die Zeiger werden bei Immutables sofort angelegt. Bei Mutables auf Vorrat. Hier kannst du auch einfach das Mutable dazu "zwingen" (es ist sanfter Druck), einen gewissen Vorrat anzulegen. Da geht es aber nur um Zeiger, also jeweils 4 Byte.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von Tom9811
    Üblicherweise werden in Framework nicht bei jeder Speicheranforderung an das Framework auch gleich Speicheranforderungen an das System geschickt.

    Wenn wir mal stillschweigend davon ausgehen, daß Objective-C malloc und die verwandten Funktionen nutzt(die Objective-C Runtime Library ist jedenfalls gegen diese Funktionen gelinkt), dann macht das Caching die malloc Implementation und nicht das Framework. Wenn man eine alloc Meldung verschickt wird immer auch malloc oder verwandte aufgerufen, die aber nicht notwendigerweise immer eine Speicheranforderung an den Kernel ergibt.

    Ich weiß nicht, ob die Objective-C Runtime Library Teil von Apples Darwin ist, sonst könnte man einfach mal einen Blick in den Sourcencode werfen. strace oder valgrind wären jetzt hilfreich, kennt jemand ein MacOS X Äquivalent?