Ich habe gerade ein Testprogramm geschrieben, um den schnellsten Weg zu finden, & amp; Geben Sie viele Objekte frei, die von shared_ptr
verwaltet wurden.
Ich habe shared_ptr
mit new
, shared_ptr
mit pool
, make_shared
, allocate_shared
versucht. Was mich überrascht, ist allocate_shared
ist langsamer als shared_ptr
mit pool
.
Ich teste den Code in vs2017+win10
mit Release Build. Die Release-Build-Einstellung ist Standard (/ O2). Ich teste es auch in gcc4.8.5+centos6.2
mit g++ -std=c++11 -O3
.
Der Code lautet:
%Vor%In meinem Computer (vs2017, Windows 10) ist das Ergebnis:
%Vor% Ich habe es auch in gcc 4.8, centos6.2 getestet, das Ergebnis ist das gleiche, das ist für die Geschwindigkeit, shared_ptr_with_pool > allocate_shared > shared_ptr_with_new > make_shared
.
Wie ich weiß, muss shared_ptr :: shared_ptr (T * p) einen kleinen Speicher zuweisen, um den Refcount und den Deleter zu halten, also muss zweimal zugeordnet werden, und der make_shared muss nur einmal zuordnen und allocate_shared muss nicht einmal einmal zugewiesen werden.
Nach meinem Verständnis sollte die Geschwindigkeitsbeziehung allocate_shared > shared_ptr_with_pool > make_shared > shared_ptr_with_new
sein, aber nicht shared_ptr_with_pool > allocate_shared > shared_ptr_with_new > make_shared
.
Könnte mir jemand den Grund nennen, sehr danke!
Aktualisierung:
Nach einigem Dig von vs2017 + windows10 habe ich std::allocate_shared
oder boost::allocate_shared
call memset(p, 0, sizeof(Packet))
gefunden, was den While-Vorgang verlangsamt.
Es liegt daran, dass einige Codes in VS2017-Bibliothekskopfzeile so aussehen:
%Vor% Der Paarkonstruktor ruft memset(addr, 0, sizeof(Pair))
auf.
Ich weiß nicht, warum der Paarkonstruktor memset
aufruft, und ich habe einen Testcode geschrieben:
Ich habe den Code mit vs2017 kompiliert und festgestellt, dass das Memset (addr, 0, 1500) aufgerufen wird. Der Asm-Code (Debug-Build, der Release-Build ist gleich) lautet:
%Vor%Wenn ich einen leeren Konstruktor hinzufüge, sieht es so aus:
%Vor%Der asm-Code (Debug-Build, der Build ist identisch) lautet:
%Vor% Die call _memset (0C510BEh)
wurde in call A::A (010A1456h)
geändert.
So sieht es aus, wenn der Typ A Konstruktor hat, der a_(std::forward<T>(t)...)
den Konstruktor aufruft, wenn Typ A keinen Konstruktor hat, der a_(std::forward<T>(t)...)
Aufruf memset(addr,0,sizeof(A))
. ( Warum? )
Der Grund für das Aufrufmemset std :: allocate_shared liegt am folgenden Code ( vs2017, xutility, in my computer, at C:\Program Files (x86)\Microsoft Visual Studio17\Community\VC\Tools\MSVC.10.25017\include
):
Der Typ von _Myval2 ist std :: _ Align_type, der definiert ist
%Vor% Der _Align_type
hat keinen Konstruktor, also den _Myval2(_STD forward<_Other2>(_Val2)...)
Aufruf memset(addr,0, sizeof(T))
.
Also habe ich die _Align_type-Definition geändert (füge einen Dummy-Konstruktor hinzu) und erneut testen. Ich habe festgestellt, dass std :: allocate_shared memset
nicht aufruft und viel schneller als zuvor.
Nachdem ich die Definition von _Align_type geändert habe, ist jetzt die Geschwindigkeit von test_allocate_shared
gleich oder etwas schneller als test_shared_ptr_with_pool
.
Bis jetzt weiß ich, warum std::allocate_shared
so langsam ist, aber ich weiß immer noch nicht warum der Code memset
aufruft, wenn Typ T keinen Konstruktor hat, aber nicht memset
aufruft, wenn T Konstruktor hat.
Ist es ein C ++ Standard?
Und, da die allocate_shared memset (sizeof (T)) nicht aufrufen sollte, ist es ein Fehler des Compilers?
Aktualisieren :
%Vor%Ich kompiliere obigen Code von vs2017, x86 Release-Build, und der Asm-Code ist:
%Vor%Es gibt immer noch ein memset (addr, 0, 1500)!
Aktualisieren :
Es scheint, es gibt einen Fehler in Visual Studio 2017 std::allocate_shared
.
Der Code versucht, perfect-forwarding ein std::_Align_type
zu konstruieren, das keinen Konstruktor hat, und so initialisiert value-initialize std::_Align_type
, also memset
.
Nach dem Lesen von warum c ++ memset (addr, 0, sizeof (T)) benutzt, um ein Objekt zu konstruieren? Standard-oder Compiler-Bug? und Standard-Initialisierung versus Null Initialisierung , jetzt ich Verstehe, warum es ein memset
gibt.
Dies liegt daran, dass das associate_shared-Werkzeug in vs2017 den Typ _Align_type
verwendet und dieser Typ keinen Konstruktor hat. Wenn allocate_shared versucht, das _Align_type
value-initialize, ruft es memset
.
Es scheint ein Fehler in vs2017.
Vor dem Bugfix, denke ich, vielleicht keine gute Idee, um es zu umgehen.
Aktualisierung:
Ich habe einen Fehlerbericht an MS gesendet, und sie haben es getan bestätige es.
Aktualisierung: Dieser Fehler existiert noch in vs2017 Update 3.
Tags und Links c++ c++11 performance shared-ptr