Speicher und Performanz Overhead von Smart Pointern

Inhaltsverzeichnis[Anzeigen]

C++ bietet vier verschiedene Smart Pointer an. Zwei davon will ich mir in diesem Artikel unter dem Aspekt Overhead in puncto Speicher und Performanz genauer anschauen. Während mein erster Kandidat std::unique_ptr den Lebenszyklus genau einer Ressource verwaltet, teilt sich mein zweiter Kandidat std::shared_ptr typischerweise seine Ressource mit anderen std::shared_ptr. Ich nehme das Ergebnis meines Tests gerne vorweg, bevor die nackten Zahlen kommen. Es gibt wenige Gründe in modernem C++, das Speichermanagment mit new und delete explizit in die Hand zu nehmen. 

 

Warum? Jetzt kommen die Fakten.

Speicher Overhead

std::unique_ptr

std::unique_ptr benötigt in der Regel keinen zusätzlichen Speicher. Das heißt, ein std::unique_ptr ist nicht größer ist als der Zeiger auf den Speicher, den er verwaltet. Warum sage ich in der Regel? Da ein std::unique_ptr mit einer Löschfunktion parametrisiert werden kann, benötigt diese natürlich Speicher. Das ist aber nicht der Standardfall.

Im Gegensatz dazu besitzt der std::shared_ptr einen kleinen Overhead.

std::shared_ptr

Mehrere std::shared_ptr teilen sich zusammen eine gemeinsame Variable. Dabei führen sie intern einen Referenzzähler mit. Das heißt, jedes Mal wenn der std::shared_ptr kopiert wird, wird der Referenzzähler erhöht, bzw. erniedrigt, wenn ein std::shared_ptr seinen Gültigkeitsbereich verlässt. Daher benötigt ein std::shared_ptr zusätzlichen Speicher für den Referenzzähler. Das ist auch schon der minimale Overhead, den ein std::shared_ptr gegenüber einem rohen Zeiger besitzt.

Performanz Overhead

Die Geschichte zur Performanz ist ein wenig komplizierter. Dazu lasse ich die Zahlen sprechen. Ein einfacher Performanztest soll Klarheit schaffen.

Der Performanztest

In dem Test fordere ich 100000000 Mal Speicher an und gib ihn wieder frei. Genau die Zeit für all diese Operationen interessiert mich.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// all.cpp

#include <chrono>
#include <iostream>

static const long long numInt= 100000000;

int main(){

  auto start = std::chrono::system_clock::now();

  for ( long long i=0 ; i < numInt; ++i){
    int* tmp(new int(i));
    delete tmp;
    // std::shared_ptr<int> tmp(new int(i));
    // std::shared_ptr<int> tmp(std::make_shared<int>(i));
    // std::unique_ptr<int> tmp(new int(i));
    // std::unique_ptr<int> tmp(std::make_unique<int>(i));
  }

  std::chrono::duration<double> dur= std::chrono::system_clock::now() - start;
  std::cout << "time native: " << dur.count() << " seconds" << std::endl;

}

 

In meinem Test stelle ich den expliziten Umgang mit new und delete (Zeile 13 und 14)  dem Einsatz von std::shared_ptr (Zeile 15), std::make_shared (Zeile 16), std::unique_ptr (Zeile 17) und std::make_unique (Zeile 18) gegenüber. Selbst in dem kleinen Programm ist Umgang mit den Smart Pointern in Zeile 15 - Zeile 18 deutlich einfacher, da die Smart Pointer in Zeile 19 ihren Gültigkeitsbereich verlassen und somit automatisch der Speicher der dynamische angelegten int Variable freigegeben wird.

Die zwei Funktionen std::make_shared (Zeile 16) und std::make_unique (Zeile 18) sind praktische Hilfsfunktionen, die ein entsprechenden Smart Pointer direkt erzeugen. Besonders interessant ist std::make_shared. Beim Anlegen eines std::shared_ptr sind zwei Speicherallokationen notwendig. Zum einen wird Speicher für die verwaltete Variable angefordert, zum anderen für den Referenzzähler. Aus diesen zwei teuren Speicheranforderungen macht std::make_shared eine. Die Performanz dankt es. std::make_unique gibt es erst seit C++14. Die ganze andere Funktionalität steht schon seit C++11 zur Verfügung.

Für meine Tests verwende ich einen den GCC 4.9.2 und den cl.exe, der Bestandteil von Microsoft Visual Studio 2015 ist. Obwohl dieser Compiler nur C++11 unterstützt, bietet er std::make_unique schon an. Damit kann ich alle Tests mit maximaler und ohne Optimierung auf Linux und Windows durchführen. Zur Ehrenrettung von cl.exe muss ich sagen, dass mein Windows PC deutlich schwächer ist als meine Linux PC. Daher liegt der Schwerpunkt meiner Analyse darauf, die Performanz des expliziten Speichermangements mit der der Smart Pointer zu vergleichen. Ich vergleiche nicht Windows mit Linux.

Hier kommen die nackten Zahlen in Sekunden.

Die nackten Zahlen

Der Einfachheit halber verzichte ich auf die Screenshots und habe die Ergebnisse bereits in einer Tabelle zusammengefasst.

comparison

Ein paar sehr interessante Erkenntnisse lassen sich aus der Tabelle ableiten.

  1. Optimierung zahlt sich aus. Im Falle von std::make_shared ist der Performanzunterschied nahezu 10 fach unter Linux. Aber auch im Falle der anderen Variationen ist die optimierte Variante um den Faktor 2 bis 3 schneller. Das gilt für Linux als auch für Windows. Wird hingegen new und delete verwendet, gibt es kein großes Optimierungspotential mehr für den Compiler.
  2. std::unique_ptr, std::make_unique und mit kleinen Abstrichen std::make_shared spielen in der gleichen Liga wie new und delete.
  3. std::shared_ptr und std::make_shared sollten nicht ohne Optimierung verwendet werden. std::shared_ptr ist selbst mit Optimierung um dem Faktor zwei langsamer als new und delete.

Mein Fazit

  • std::unique_ptr besitz keine Speicher und Performanz Overhead gegenüber dem expliziten Speichermanagement mit new und delete. Das ist großartig. Bietet std::unique_ptr doch einen deutlichen Mehrwert an, indem er automatisch den Lebenszyklus seiner Ressource verwaltet und dies, ohne irgendwelche zusätzliche Kosten zu verursachen.
  • Für std::shared_ptr ist mein Fazit schon ein bisschen schwieriger. Ja, ich gebe zu, dass std::shared_ptr ca. um den Faktor zwei langsamer ist als new und delete. Aber, diese Rechnung ist falsch, denn std::shared_ptr teilen sich ihre Objekte. Das heißt insbesondere, dass der erste std::shared_ptr zwar Speicher für das Objekt und den Referenzzähler einmalig anfordern muss, das heißt aber auch, dass jeder weitere std::shared_ptr die Verwaltungsstruktur für die geteilte Variable mit nutzen kann.

Daher will ich mich gerne wiederholen. Es gibt wenige Gründe in modernem C++, das Speichermanagment mit new und delete explizit in die Hand zu nehmen.

Wie geht's weiter?

Nach diesem Plädoyer für Smart Pointer folgen im nächsten Artikel die Details zu dem std::unique_ptr.

 

 

 

 

 

 

title page smalltitle page small Go to Leanpub/cpplibrary "What every professional C++ programmer should know about the C++ standard library".   Hole dir dein E-Book. Unterstütze meinen Blog.

 

Kommentare   

0 #1 Tom 2016-07-02 04:18
Ӏ amm genuinely thankful to tɦe holder of this website who has shared
tҺis fantastic paragraph at ɑt this plɑce.
Zitieren
0 #2 three times 2016-08-23 22:08
Dead composed subject matter, Really enjoyed reading through.
Zitieren
0 #3 business loans 2016-09-05 12:36
TҺere is dᥱfinately a great deal to ⅼearn aƅout tһis topic.
I likе ɑll of the points you have made.
Zitieren
0 #4 business finance 2016-09-06 09:27
Heⅼlo there, I discoᴠеred your site via Google while searching for a similar topic, your site got here up,
it looks good. I've ƅоokmarked it in my google bookmarks.


Heⅼlo there, just became aware of your bⅼog through Google,
and found that it's truly іnformative. I'm gonna be careful for brussels.
I'lⅼ apprecіate should you contіnue this in futuгe.
A lot of folks might bе benefited out of your writing. CҺeeгs!
Zitieren
0 #5 Www.credant.eu 2016-10-02 13:08
Doess your website һave ɑ contact pagе? I'm haѵing trouble locating
it but, ӏ'd like to shoot you an e-mail. I've
ցot some suggestions fⲟr your blog you might be interestеd іn hearing.
Еither ԝay, ɡreat blog and I look forward tо seeing it improve
oνer tіme.
Zitieren
0 #6 dc snapback 2016-11-23 10:47
Hello to every one, the contents existing at this web site are in fact amazing for people knowledge,
well, keep up the good work fellows.
Zitieren
0 #7 giamgiachotui.com 2016-12-12 17:51
What's Taking place i am new to this, I stumbled upon this
I've found It absolutely useful and it has aided me out loads.
I am hoping to contribute & aid other customers like its helped
me. Great job.
Zitieren

Kommentar schreiben


Modernes C++

Abonniere den Newsletter

Inklusive zwei Artikel meines Buchs
Introduction und Multithreading

Beiträge-Archiv

Sourcecode

Neuste Kommentare