stringtranslate.com

Rastreo de pila

En informática , un seguimiento de pila (también llamado seguimiento de pila [1] o seguimiento de pila [2] ) es un informe de los marcos de pila activos en un punto determinado en el tiempo durante la ejecución de un programa . Cuando se ejecuta un programa, la memoria a menudo se asigna dinámicamente en dos lugares: la pila y el montón . La memoria se asigna continuamente en una pila pero no en un montón, lo que refleja sus nombres. La pila también se refiere a una construcción de programación, por lo que para diferenciarla, esta pila se conoce como la pila de llamadas de función del programa . Técnicamente, una vez que se ha asignado un bloque de memoria en la pila, no se puede eliminar fácilmente ya que puede haber otros bloques de memoria que se asignaron antes. Cada vez que se llama a una función en un programa, se asigna un bloque de memoria llamado registro de activación en la parte superior de la pila de llamadas. Generalmente, el registro de activación almacena los argumentos y las variables locales de la función. Lo que contiene exactamente y cómo se presenta está determinado por la convención de llamada .

Los programadores suelen utilizar el seguimiento de pila durante la depuración interactiva y post mortem . Los usuarios finales pueden ver un seguimiento de pila como parte de un mensaje de error , que luego pueden informar a un programador.

Un seguimiento de pila permite rastrear la secuencia de funciones anidadas llamadas, hasta el punto en el que se genera el seguimiento de pila. En un escenario de análisis posterior, esto se extiende hasta la función en la que se produjo el error (pero no necesariamente fue su causa). Las llamadas hermanas no aparecen en un seguimiento de pila.

Soporte de idiomas

Muchos lenguajes de programación, incluidos Java [3] y C# [4] , tienen soporte integrado para recuperar el seguimiento de la pila actual a través de llamadas al sistema. Antes de std::stacktraceque se agregara en la biblioteca estándar como un contenedor para std::stacktrace_entry, pre- C++23 no tiene soporte integrado para hacer esto, pero los usuarios de C++ pueden recuperar seguimientos de pila con (por ejemplo) la biblioteca stacktrace . En JavaScript , las excepciones contienen una stackpropiedad que contiene la pila desde el lugar donde se lanzó.

Pitón

A modo de ejemplo, el siguiente programa Python contiene un error.

definición  a (): yo  =  0 j  =  b ( yo ) volver  jdefinición  b ( z ): k  =  5 si  z  ==  0 : c () devuelve  k  +  zdefinición  c (): error ()a ()

Al ejecutar el programa bajo el intérprete estándar de Python se produce el siguiente mensaje de error.

Rastreo (última llamada reciente): Archivo "file.py" , línea 15 , en <módulo> a () Archivo "file.py" , línea 3 , en a j = b ( i ) Archivo "file.py" , línea 9 , en b c () Archivo "file.py" , línea 13 , en c error () NameError : el nombre 'error' no está definido      

El seguimiento de la pila muestra dónde se produce el error, concretamente en la cfunción. También muestra que la cfunción fue llamada por b, que fue llamada por a, que a su vez fue llamado por el código en la línea 15 (la última línea) del programa. Los registros de activación para cada una de estas tres funciones se organizarían en una pila de modo que la afunción ocuparía la parte inferior de la pila y la cfunción ocuparía la parte superior de la pila.

Java

En Java , los seguimientos de pila se pueden volcar manualmente con Thread.dumpStack()[5] Tome la siguiente entrada:

clase pública Main {    public static void principal ( cadena args [] ) {      demostración (); } demostración estática vacía () {    demo1 (); } void estático demo1 () {    demo2 (); } void estático demo2 () {    demo3 (); } void estático demo3 () {    Hilo .dumpStack ( ) ; }}

La excepción enumera las funciones en orden descendente, por lo que la llamada más interna es la primera.

java.lang . Excepción : Rastreo de pila en java.lang . Subproceso.dumpStack ( Subproceso.java:1336 ) en Main.demo3 ( Main.java:15 ) en Main.demo2 ( Main.java:12 ) en Main.demo1 ( Main.java:9 ) en Main.demo ( Main.java:6 ) en Main.main ( Main.java:3 )              

C y C++

Tanto C como C++ (pre- C++23 ) no tienen soporte nativo para obtener seguimientos de pila, pero bibliotecas como glibc y boost proporcionan esta funcionalidad. [6] [7] En estos lenguajes, algunas optimizaciones del compilador pueden interferir con la información de la pila de llamadas que se puede recuperar en tiempo de ejecución. Por ejemplo, la inserción en línea puede causar marcos de pila faltantes, las optimizaciones de llamadas de cola pueden reemplazar un marco de pila por otro y la eliminación del puntero de marco puede evitar que las herramientas de análisis de la pila de llamadas interpreten correctamente el contenido de la pila de llamadas. [6]

Por ejemplo, la función de glibc backtrace()devuelve una salida con la función del programa y la dirección de memoria.

. / a . out () [ 0x40067f ] . / a . out () [ 0x4006fe ] . / a . out () [ 0x40070a ] / lib / x86_64 - linux - gnu / libc . so .6 ( __libc_start_main + 0xf5 ) [ 0x7f7e60738f45 ] . / a . out () [ 0x400599 ]     

A partir de C++23 , los seguimientos de pila se pueden volcar manualmente imprimiendo el valor devuelto por la función miembro estática std::stacktrace::current(): [8]

std :: cout << std :: stacktrace :: actual () << '\n' ;    

Óxido

Rust tiene dos tipos de errores. Las funciones que utilizan la macro panic son "irrecuperables" y el hilo actual se envenena y experimenta un desenrollado de la pila. Las funciones que devuelven a std::result::Resultson "recuperables" y se pueden manejar con elegancia. [9] Sin embargo, los errores recuperables no pueden generar un seguimiento de la pila, ya que se agregan manualmente y no son el resultado de un error de tiempo de ejecución.

A partir de junio de 2021, Rust cuenta con soporte experimental para seguimientos de pila en errores irrecuperables. Rust admite la impresión en stderr cuando un subproceso entra en pánico, pero debe habilitarse configurando la RUST_BACKTRACE variable de entorno . [10]

Cuando están habilitados, dichos seguimientos se ven similares a los que se muestran a continuación, con la llamada más reciente primero.

hilo ' principal ' entró en pánico en ' ejecutar_a_pánico ' , principal.rs : 3 pila backtrace : 0 : std :: sys :: imp :: backtrace :: tracing :: imp :: unwind_backtrace 1 : std :: en pánico :: gancho_predeterminado :: {{ cierre }} 2 : std :: en pánico :: gancho_predeterminado 3 : std :: en pánico :: rust_panic_with_hook 4 : std :: en pánico :: begin_panic 5 : futuros :: tarea_impl :: con 6 : futuros :: tarea_impl :: aparcar .. .            

Véase también

Referencias

  1. ^ "libc manual: backtraces". gnu.org . Consultado el 8 de julio de 2014 .
  2. ^ "traceback — Imprimir o recuperar un seguimiento de pila". python.org . Consultado el 8 de julio de 2014 .
  3. ^ "Thread (Java SE 16 y JDK 16)". Especificación de API de Java Platform Standard Edition y Java Development Kit versión 16 . 2021-03-04 . Consultado el 2021-07-04 .
  4. ^ "Propiedad Environment.StackTrace (sistema)". Microsoft Docs . 2021-05-07 . Consultado el 2021-07-04 .
  5. ^ "Hilo (Java Platform SE 8)". docs.oracle.com . Consultado el 15 de junio de 2021 .
  6. ^ ab "Backtraces (La biblioteca C de GNU)". www.gnu.org . Consultado el 15 de junio de 2021 .
  7. ^ "Primeros pasos - 1.76.0". www.boost.org . Consultado el 15 de junio de 2021 .
  8. ^ "Borrador de trabajo, estándar para el lenguaje de programación C++" (PDF) . open-std.org . ISO/IEC. 2021-10-23. p. 766.
  9. ^ "Desenrollando el rustonomicon - Rust". doc.rust-lang.org .
  10. ^ "std::backtrace - Rust". doc.rust-lang.org . Consultado el 15 de junio de 2021 .