tl; dr: Es ist nicht so, dass die dynamische Speicherzuweisung von Natur aus nicht deterministisch ist (wie Sie es anhand identischer Ausführungspfade definiert haben). Es ist so, dass es Ihr Programm im Allgemeinen unvorhersehbar macht . Insbesondere können Sie nicht vorhersagen, ob der Allokator angesichts einer beliebigen Folge von Eingaben ausfallen könnte.
Sie könnten einen nicht deterministischen Allokator haben. Dies ist außerhalb Ihrer Echtzeitwelt üblich, in der Betriebssysteme beispielsweise die Randomisierung des Adresslayouts verwenden. Das würde Ihr Programm natürlich nicht deterministisch machen.
Dies ist jedoch kein interessanter Fall. Nehmen wir also einen perfekt deterministischen Allokator an: Dieselbe Reihenfolge von Zuweisungen und Freigaben führt immer zu denselben Blöcken an denselben Standorten, und diese Zuweisungen und Freigaben haben immer eine begrenzte Laufzeit.
Jetzt kann Ihr Programm deterministisch sein: Der gleiche Satz von Eingaben führt zu genau dem gleichen Ausführungspfad.
Das Problem ist, dass Sie beim Zuweisen und Freigeben von Speicher als Reaktion auf Eingaben nicht vorhersagen können, ob eine Zuweisung jemals fehlschlagen wird (und ein Fehler ist keine Option).
Erstens könnte Ihr Programm Speicher verlieren. Wenn es also auf unbestimmte Zeit ausgeführt werden muss, schlägt eine Zuordnung möglicherweise fehl.
Aber selbst wenn Sie nachweisen können, dass keine Lecks vorhanden sind, müssen Sie wissen, dass es niemals eine Eingabesequenz gibt, die mehr Speicher als verfügbar erfordern könnte.
Aber selbst wenn Sie nachweisen können, dass das Programm niemals mehr Speicher benötigt als verfügbar ist, kann der Allokator abhängig von der Reihenfolge der Zuweisungen und Freigaben den Speicher fragmentieren und somit möglicherweise keinen zusammenhängenden Block finden, um eine Zuordnung zu erfüllen, obwohl Insgesamt ist genügend freier Speicher vorhanden.
Es ist sehr schwierig zu beweisen, dass es keine Folge von Eingaben gibt, die zu einer pathologischen Fragmentierung führen.
Sie können Allokatoren entwerfen, um sicherzustellen, dass keine Fragmentierung auftritt (z. B. durch Zuweisen von Blöcken mit nur einer Größe). Dies stellt jedoch eine erhebliche Einschränkung für den Anrufer dar und erhöht möglicherweise den aufgrund der Verschwendung erforderlichen Speicherplatz. Und der Anrufer muss immer noch nachweisen, dass es keine Lecks gibt und dass unabhängig von der Reihenfolge der Eingaben eine zufriedenstellende Obergrenze für den Gesamtspeicher erforderlich ist. Diese Belastung ist so hoch, dass es tatsächlich einfacher ist, das System so zu gestalten, dass es keine dynamische Speicherzuweisung verwendet.