c++ performance heap-memory stack-memory

c++ - ¿Por qué la asignación de memoria de montón es mucho más rápida que la asignación de memoria de pila?



performance heap-memory (3)

He intentado asignar espacio para 10 ^ 7 enteros en la memoria de pila y pila para ver cuál es más rápido. Obviamente, la asignación en la memoria de almacenamiento dinámico fue mucho más rápida, pero no entiendo la razón.

#include <bits/stdc++.h> #include <chrono> using namespace std; using namespace std::chrono; int main() { high_resolution_clock::time_point t1 = high_resolution_clock::now(); int *p = new int[1e7]; high_resolution_clock::time_point t2 = high_resolution_clock::now(); auto duration = duration_cast<microseconds>( t2 - t1 ).count(); cout << duration / 1e6 << "/n"; // 5e-06 t1 = high_resolution_clock::now(); vector<int> v(1e7); t2 = high_resolution_clock::now(); duration = duration_cast<microseconds>( t2 - t1 ).count(); cout << duration / 1e6 << "/n"; // 0.112284 return 0; }


Otras respuestas señalaron que hay al menos una inicialización "oculta" en el constructor de vectores.

Pero su ejemplo tiene otro problema: tal vez ni siquiera mide lo que cree que hace. La evaluación comparativa del código no optimizado en C ++ no tiene sentido y el código optimizado correctamente es difícil.

Echemos un vistazo a su ejemplo (modificado para facilitar la lectura) compilado por Clang con un nivel de optimización -O3 : enlace godbolt .

double test1() { high_resolution_clock::time_point t1 = high_resolution_clock::now(); int *p = new int[1e7]; high_resolution_clock::time_point t2 = high_resolution_clock::now(); auto duration = duration_cast<microseconds>( t2 - t1 ).count(); return duration / 1e6; // 5e-06 }

compilado a:

test1(): # @test1() push rbx call std::chrono::_V2::system_clock::now() mov rbx, rax call std::chrono::_V2::system_clock::now() sub rax, rbx movabs rcx, 2361183241434822607 imul rcx mov rax, rdx shr rax, 63 sar rdx, 7 add rdx, rax cvtsi2sd xmm0, rdx divsd xmm0, qword ptr [rip + .LCPI0_0] pop rbx ret .LCPI1_0: .quad 4696837146684686336 # double 1.0E+6

¡La primera parte ni siquiera llama al operador nuevo! El compilador vio a través de su programa y se dio cuenta de que nunca utilizó la matriz asignada, por lo que eliminó la asignación del ejecutable resultante.

Entonces, la primera parte de su programa no asigna la matriz en el montón cuando se compila con tales configuraciones, lo que hace que las mediciones no tengan sentido.

Recomiendo leer sobre benchmarking y usar marcos de micro benchmark especializados para hacer tales pruebas. Eche un vistazo a Google Benchmark (y QuickBench línea) y su documentación.


Solo soy un principiante, pero déjame dar lo que entiendo principalmente para ponerme a prueba.

En

int *p = new int[1e7];

está asignando memoria consecutiva para 10 millones de enteros en el montón.

En

vector<int> v(1e7);

está asignando en la memoria de pila para un objeto vector<int> . Entre los miembros de ese objeto hay un puntero a un int[1e7] en el montón, que también se asigna. Además, todos los valores en él se inicializan con el valor de int() (con 0s). Ver constructor (2) de std::vector .


new int[1e7] asigna espacio para los valores 1e7 int y no los inicializa.

vector<int> v(1e7); crea un objeto vector<int> en la pila, y el constructor para ese objeto asigna espacio para 1e7 valores int en el montón. También inicializa cada valor int a 0.

La diferencia en velocidad se debe a la inicialización.

Para comparar la velocidad de la asignación de la pila, debe asignar una matriz en la pila:

int data[1e7];

pero tenga cuidado: hay una buena posibilidad de que esto falle porque la pila no es lo suficientemente grande para una matriz tan grande.