uso trap tag stop sort songs solucion sobre sirve sexuales reggaeton quitar que programacion preguntas para opinion memory_management management libros librerias las inicia ingenieros iglesia funciones funcion estadisticas escuelas error ejemplos code cientificos challenge cerr celular canciones blue articulos articulo adiccion abusos c++ memory-management real-time micro-optimization systems-programming

c++ - trap - tag de las 20 preguntas



Sobre el uso y abuso de la aloca. (5)

Estoy trabajando en un sistema de procesamiento de eventos en tiempo real. Me gustaría minimizar la cantidad de llamadas en mi código que tienen un tiempo no determinista. Necesito construir un mensaje que consta de cadenas, números, marcas de tiempo y GUID. Probablemente un std::vector of boost::variant ''s.

Siempre he querido usar alloca en códigos pasados ​​de naturaleza similar. Sin embargo, cuando uno mira en la literatura de programación de sistemas, siempre hay precauciones masivas contra esta llamada de función. Personalmente, no puedo pensar en una máquina de clase servidor en los últimos 15 años que no tenga memoria virtual, y sé a ciencia cierta que la pila de ventanas crece una página virtual de memoria virtual, por lo que supongo Los unicos también lo hacen. No hay pared de ladrillos aquí (ya), la pila es tan probable que se quede sin espacio como el montón, ¿entonces qué da? ¿Por qué la gente no se está volviendo loca por Aloca? Puedo pensar en muchos casos de uso del uso responsable de alloca (¿alguien está procesando cadenas?).

De todos modos, decidí probar la diferencia de rendimiento (ver más abajo) y hay una diferencia de velocidad de 5 veces entre alloca y malloc (la prueba capta cómo usaría alloca). Entonces, ¿han cambiado las cosas? ¿Deberíamos lanzar una precaución al viento y usar alloca (envuelta en un std::allocator ) siempre que podamos estar absolutamente seguros de la vida útil de nuestros objetos?

Estoy cansado de vivir con miedo!

Editar:

Ok, hay límites, para Windows es un límite de tiempo de enlace. Para Unix parece ser modificable. Parece que un asignador de memoria alineado a la página está en orden: D ¿Alguien sabe de una implementación portátil de propósito general: D?

Código:

#include <stdlib.h> #include <time.h> #include <boost/date_time/posix_time/posix_time.hpp> #include <iostream> using namespace boost::posix_time; int random_string_size() { return ( (rand() % 1023) +1 ); } int random_vector_size() { return ( (rand() % 31) +1); } void alloca_test() { int vec_sz = random_vector_size(); void ** vec = (void **) alloca(vec_sz * sizeof(void *)); for(int i = 0 ; i < vec_sz ; i++) { vec[i] = alloca(random_string_size()); } } void malloc_test() { int vec_sz = random_vector_size(); void ** vec = (void **) malloc(vec_sz * sizeof(void *)); for(int i = 0 ; i < vec_sz ; i++) { vec[i] = malloc(random_string_size()); } for(int i = 0 ; i < vec_sz ; i++) { free(vec[i]); } free(vec); } int main() { srand( time(NULL) ); ptime now; ptime after; int test_repeat = 100; int times = 100000; time_duration alloc_total; for(int ii=0; ii < test_repeat; ++ii) { now = microsec_clock::local_time(); for(int i =0 ; i < times ; ++i) { alloca_test(); } after = microsec_clock::local_time(); alloc_total += after -now; } std::cout << "alloca_time: " << alloc_total/test_repeat << std::endl; time_duration malloc_total; for(int ii=0; ii < test_repeat; ++ii) { now = microsec_clock::local_time(); for(int i =0 ; i < times ; ++i) { malloc_test(); } after = microsec_clock::local_time(); malloc_total += after-now; } std::cout << "malloc_time: " << malloc_total/test_repeat << std::endl; }

salida:

hassan@hassan-desktop:~/test$ ./a.out alloca_time: 00:00:00.056302 malloc_time: 00:00:00.260059 hassan@hassan-desktop:~/test$ ./a.out alloca_time: 00:00:00.056229 malloc_time: 00:00:00.256374 hassan@hassan-desktop:~/test$ ./a.out alloca_time: 00:00:00.056119 malloc_time: 00:00:00.265731

--Editar: Resultados en home machine, clang y google perftools--

G++ without any optimization flags alloca_time: 00:00:00.025785 malloc_time: 00:00:00.106345 G++ -O3 alloca_time: 00:00:00.021838 cmalloc_time: 00:00:00.111039 Clang no flags alloca_time: 00:00:00.025503 malloc_time: 00:00:00.104551 Clang -O3 (alloca become magically faster) alloca_time: 00:00:00.013028 malloc_time: 00:00:00.101729 g++ -O3 perftools alloca_time: 00:00:00.021137 malloc_time: 00:00:00.043913 clang++ -O3 perftools (The sweet spot) alloca_time: 00:00:00.013969 malloc_time: 00:00:00.044468


Bueno, en primer lugar, aunque haya mucha memoria virtual no significa que su proceso pueda llenarlo. En * nix hay límites de tamaño de pila, mientras que el montón es mucho más indulgente.

Si solo va a asignar unos pocos cientos / miles de bytes, asegúrese de seguir adelante. Cualquier cosa más allá de eso dependerá de los límites (ulimit) que se encuentren en cada sistema, y ​​eso es solo una receta para el desastre.

¿Por qué el uso de alloca () no se considera una buena práctica?

En mi cuadro de desarrollo en el trabajo (Gentoo) tengo un límite de tamaño de pila predeterminado de 8192 kb. Eso no es muy grande, y si alloca desborda la pila, entonces el comportamiento es indefinido.


Creo que necesitas ser un poco cuidadoso para entender qué es en realidad la alianza. A diferencia de malloc que va al montón, busca en cubos y listas enlazadas de varios buffers, alloca simplemente toma su registro de pila (ESP en x86) y lo mueve para crear un "agujero" en la pila de su hilo donde puede almacenar lo que quiera. Es por eso que es súper rápido, solo una (o pocas) instrucciones de ensamblaje.

Así que, como otros señalaron, no es la "memoria virtual" lo que debe preocupar, sino el tamaño reservado para la pila. Aunque otros se limitan a "unos pocos cientos de bytes", siempre que conozca su aplicación y tenga cuidado, hemos asignado hasta 256 kb sin ningún problema (el tamaño de pila predeterminado, al menos para Visual Studio, es de 1 MB y siempre puede aumentarlo si es necesario).

Además, realmente no puede usar alloca como un asignador de propósito general (es decir, envolverlo dentro de otra función) porque cualquiera que sea la asignación de memoria que le asigne, esa memoria desaparecerá cuando se haga estallar el marco de la pila para la función actual (es decir, cuando la función se cierre).

También he visto a algunas personas decir que alloca no es completamente compatible con varias plataformas, pero si está escribiendo una aplicación específica para una plataforma específica y tiene la opción de utilizar alloca, a veces es la mejor opción que tiene, siempre y cuando usted entiende las implicaciones de aumentar el uso de pila.


En primer lugar, es porque la memoria de la alloca es muy difícil de controlar. Se desata, muere a la primera oportunidad, lo que hace que no sea muy útil. Además, alloca tiene algunos efectos secundarios desafortunados, y esos efectos secundarios son que las variables de pila regulares ahora tienen que indexarse ​​dinámicamente en lugar de constantes, lo que puede afectar su rendimiento incluso en las operaciones básicas que acceden a ellas y consume espacio de registro / pila para almacenar la dinámica. compensaciones Esto significa que el costo real de usar alloca no se registra solo en el tiempo que tarda la función en regresar. Además, creo que la memoria de pila es muy limitada en comparación con la memoria de pila: en Windows, el límite de pila es de 8 MB por defecto, mientras que la pila puede ser casi la totalidad del espacio de direcciones del usuario. Más que eso, en última instancia, cualquier información que desee devolver debe estar en el montón, por lo que también puede usarla como espacio de trabajo.


La pila de ventanas no crece, su tamaño reservado se establece en el momento del enlace, pero las páginas dentro de este tamaño solo se confirmarán según sea necesario. Consulte http://msdn.microsoft.com/en-us/library/ms686774%28v=vs.85%29.asp . Como el tamaño reservado predeterminado es de 1Mb, puede fácilmente superar este valor al utilizar alloca() .


Un punto que aún no se ha podido hacer es que la pila es contigua , mientras que el montón no lo es. En general, no es cierto que la pila se quede sin memoria como el montón.

En C ++, es muy común ver las instancias de objetos declaradas como locales, que es algo así como una alloca pero de memoria estructurada en lugar de un bloque de N bytes. alloca vez pueda pensar en esto como un homenaje a su punto principal, que es eso. Un buen uso de la memoria basada en la pila es una buena idea. Preferiría hacer eso (declarar una instancia de objeto como un RAII local) que usar malloc (o alloca ) en un programa C ++. Todas esas llamadas free para hacer la excepción segura ...

Esto generalmente asume que el alcance del objeto se limita a esta función y sus funciones llamadas. Si ese no es el caso, el uso de memoria basada en pila generalmente no es una buena idea de todos modos.