Warum programmiert ihr in C und was?
-
dachschaden schrieb:
Wenn der Speicher dann knapp wird, muss die Anwendung selbst halt ordentlich handeln, dass sie jetzt keinen Speicher bekommt.
Und genau das ist z.B. in echtzeitfähigen Systemen ein Riesenproblem. Deshalb bin ich überzeugt davon, dass maximale Verfügbarkeit letztlich nur durch direkten Speicherzugriff zu erreichen ist und nicht durch irgendwelche Zwischensoftware, die Pages umsortiert und Festplatte/Flash als Buffer für RAM benutzt.
Große OS (zum Beispiel Windows) treiben es auf die Spitze, indem sie sogar Code einer Anwendung auf die Festplatte auslagern. Das hat dann zur Folge, dass ein selten genutzter Befehl bzw. Menupunkt zu mehreren Sekunden Wartezeit führt. Sogar das OS selbst friert manchmal einfach mal kurz ein, wenn du nur 4GB RAM hast.
-
dachschaden schrieb:
Ich habe hier gerade ein C++-Binary rumfliegen, welches so an das halbe Mebibyte groß ist. Verwendet Boost. Da sind so vielleicht 2 Funktionen von 100, die tatsächlich vom Programmierer kommen, der Rest kommt von Boost oder iostream oder macht string-Konvertierungen oder weiß der Geier. Würde mal so schätzen, mindestens 80% sind nur ctor/dtor-Aufrufe und ein bisschen Stack Unwinding.
Ok...
Das gleiche Problem haben wir bei C auch. Dieses ganze Konstrukt um malloc mag für Embedded-Systeme (wo z.B. alle Programme in Ring 0 laufen und überall lesen und schreiben können und sich alle Programme einen zentralen Heap teilen) vielleicht noch Sinn ergeben. Aber für einen großen Teil der Programme gilt das nicht.
Nur mal eine Vermutung:
Kann es sein, dass irgentein Java Jüngling ein Projekt in C programmiert hat, sein Code mit malloc() verseucht hat, du das Projekt übernommen hast, festgestellt hast, dass das malloc() viel Zeit frisst und deswegen eine neue malloc() Implementierung gemacht hat?
dachschaden schrieb:
Und wenn ich all diesen Scheiß wegnehme und mir mein eigenes Interface zusammenbastel, in dem ich auf Feature-Creep-Scheiß verzichte und mir lieber die Möglichkeit gebe, Page-Walks zu vermeiden, und dabei noch auf 32 KiB-Binaries komme, mit einem Verhältnis von 35/1 LOC (eine LOC in der Anwendung kommt auf 35 LOC in der Bibliothek), dann weiß ich, dass ich was richtig gemacht habe.
Entschuldigung dass ich das mal sage, aber für meinen Geschmack solltest du dein aufbrausendes Temperament mal zügeln. Gerade bei der Programmierung steckt der Teufel im Detail, die so manche voreilige Lösung scheitern lässt.
Was juckt mich ehrlich gesagt die Binary Größe? Was? Wenn es dir um Performance geht, dann suche dir die Bottlenecks mittels Profiler oder anderem und optimiere diese. Und wenn jemand O(n^2) mal malloc() auffruft, dann würde ich erst mal überprüfen ob dies überhaupt notwendig ist!
Und wenn 80% von 512 kByte Konstruktor, Destruktor Aufrufe sind, dann würde ich das erst einmal mittels der Map File überprüfen. Und wenn das stimmt, dann muss der Quellcode vor new() Aufrufen überquellen. Also würde mir den Verantwortlichen schnappen und ihm gehörig den Marsch blasen. Denn das komplette Programm-Design ist kaputt. Und dann hilft nur eins: neuprogrammieren!
-
Bitte ein Bit schrieb:
Kann es sein, dass irgentein Java Jüngling ein Projekt in C programmiert hat, sein Code mit malloc() verseucht hat, du das Projekt übernommen hast, festgestellt hast, dass das malloc() viel Zeit frisst und deswegen eine neue malloc() Implementierung gemacht hat?
Wie kommst du denn auf diese Idee?
Nein, das hat nix mit Java zu tun, eher mit Perl.
Vor vielen Monden habe ich mal einen Webcrawler geschrieben. Wer Perl kennt, weiß, dass der Threading-Support echt grausam ist (oder zumindest war, als ich den geschrieben habe), und so nach 25 "Threads" und vier Stunden Laufzeit war der Arbeitsspeicher ohne Not komplett voll. Das war damals noch eine 16-GiB-Maschine ... ich weiß bis heute nicht, warum Perl so viel Speicher verbraucht hat, und mir ist es auch egal.Und als ich das in C nachgeschrieben habe, wurde das Laufzeitverhalten zwar immer besser, aber mit der Zeit tauchten weitere Flaschenhälse auf, wenn richtig viele Threads laufen und Speicher anfordern.
Irgendwann hatte ich das dann auch gefixt. Und dann sollte der Code noch in zig anderen Programmen einfließen. Und dann musste ich intelligent abstrahieren.
Bitte ein Bit schrieb:
Entschuldigung dass ich das mal sage, aber für meinen Geschmack solltest du dein aufbrausendes Temperament mal zügeln. Gerade bei der Programmierung steckt der Teufel im Detail, die so manche voreilige Lösung scheitern lässt.
Da du nicht wissen kannst, wie das Interface aussieht, dass ich geschrieben habe, kannst du gar nicht beurteilen, ob ich eventuelle Details außer Acht gelassen habe.
Ich bin bei einigen Sachen fett auf's Maul geflogen, aber habe auch etliche Erkenntnisse daraus gezogen.
Bitte ein Bit schrieb:
Was juckt mich ehrlich gesagt die Binary Größe? Was?
Noch nie ein Programm disassembliert, weil der Quellcode nicht (mehr) vorhanden war?
Wenn du halt keine Programme reverse-engeineerst, dann braucht dich das nicht kümmern, stimmt schon. Genau genommen brauchen dich dann auch Optimierungen nicht zu kümmern, solange es nur schnell genug ist.
Nur wenn du eine zentrale Speicherverwaltungslib hast, über die du tausend tolle Sachen machen willst, dann kümmert es dich vielleicht. Weil der Code dann nicht nur Programm A berührt, sondern auch Programm B - Z.
Bitte ein Bit schrieb:
Wenn es dir um Performance geht, dann suche dir die Bottlenecks mittels Profiler oder anderem und optimiere diese. Und wenn jemand O(n^2) mal malloc() auffruft, dann würde ich erst mal überprüfen ob dies überhaupt notwendig ist!
Das Überprüfen, ob es notwendig ist, ist doch gar nicht das Problem!
Vor kurzem habe ich mal einen Blick in XFE geworfen, ein "leichtgewichtiger" Dateimanager auf Linux, der halt seine Display-Verbindungen nicht richtig geschlossen hat, wenn ein Subprozess gestartet werden sollte, und irgendwann hat X dann gestreikt und keine weiteren Verbindungen aufgemacht, und weil der Code darauf nicht prüfte, ist der Manager dann halt gestorben.Warum ich das erzähle? Weil das Herrausfinden des Fehlers gar nicht mal schwer war - beim Starten des Programms holt sich die Anwendung bereits eine X-Verbindung, die kann dann überall durchgereicht werden. Aber wir reden hier von einem Zeiger auf eine Struct, die eine X-Verbindung exportiert. Bei meinem Interface ist es möglich, dass TCP-Payload, entchunkter HTTP-Content und decodierter HTTP-Content im gleichen Speicherblock liegen, und dann soll noch was in den freien Speicher geschrieben werden, den wir am Ende haben. Und wenn wir ein
realloc
machen, zerstört das absolute Pointer auf bestimmte Datensektionen.Und sowas taucht dann bis zu 35 Mal in verschiedenen Programmen auf - von denen ich weiß. Das Problem sind dann nicht nur die Flaschenhälse, sondern auch, den Code wartbar zu halten. Und dafür möchtest du so viel Code wie zentral haben.
Bitte ein Bit schrieb:
Und wenn 80% von 512 kByte Konstruktor, Destruktor Aufrufe sind, dann würde ich das erst einmal mittels der Map File überprüfen. Und wenn das stimmt, dann muss der Quellcode vor new() Aufrufen überquellen. Also würde mir den Verantwortlichen schnappen und ihm gehörig den Marsch blasen. Denn das komplette Programm-Design ist kaputt. Und dann hilft nur eins: neuprogrammieren!
Ich weiß nicht, in welcher Welt du lebst, aber in meiner Welt hat man diesen Luxus nicht unbedingt. Weil der Programmierer längst das Weite gesucht hat, oder eh nie zur Verfügung stand. Und warum sollte man überhaupt in Betracht ziehen, das Programm neuzuschreiben? Vom Design her ist doch nichts zu beanstanden hier!
Und die Programmierer, die ich kenne, lassen das dann auch so stehen.
-
das mit deiner selbstgeschriebenen speicherverwaltung klingt sehr interessant. hast du da zufällig eine doku (für dich) geschrieben die ich lesen könnte?
ich würd gern die internen unterschiede und vorteile deiner variante gegenüber malloc verstehen. um ehrlich zu sein, weiß ich selbst nicht wie malloc intern arbeitet (es tut halt), so das ich da auch noch was lernen konnte.wenn du den code/doku für dich behalten willst kann ich das auch verstehen, kein problem.
-
tenim schrieb:
um ehrlich zu sein, weiß ich selbst nicht wie malloc intern arbeitet (es tut halt), so das ich da auch noch was lernen konnte.
Im Prinzip arbeitet malloc auf Basis verketteter Listen. Es zerstückelt einen größeren Speicherblock in kleine Schnipsel. Hier ein paar Beispiele: http://www.rtos.be/2014/05/open-source-implementations-of-malloc/