Leí que Golang Language administra la memoria de forma inteligente. Usando el análisis de escape, puede no asignar la memoria al llamar a NEW, y viceversa. ¿Puede Golang asignar memoria con tal notación var bob * Person = & Person {2, 3}? O siempre el puntero apuntará a la pila

0
Nakem1 9 jun. 2021 a las 03:02

3 respuestas

La mejor respuesta

El puntero puede escapar al montón, o no puede, depende de su caso de uso. El compilador es bastante inteligente. P.ej. dado:

type Person struct {
    b, c int
}


func foo(b, c int) int {
    bob := &Person{b, c}
    return bob.b
}

La función foo se compilará en:

    TEXT    "".foo(SB)
    MOVQ    "".b+8(SP), AX
    MOVQ    AX, "".~r2+24(SP)
    RET

Todo está en la pila aquí, porque a pesar de que bob es un puntero, no escapa del alcance de esta función.

Sin embargo, si consideramos una ligera modificación (aunque artificial):

var globalBob *Person

func foo(b, c int) int {
    bob := &Person{b, c}
    globalBob = bob
    return bob.b
}

Entonces bob se escapa, y foo se compilará a:

    TEXT    "".foo(SB), ABIInternal, $24-24
    MOVQ    (TLS), CX
    CMPQ    SP, 16(CX)
    PCDATA  $0, $-2
    JLS     foo_pc115
    PCDATA  $0, $-1
    SUBQ    $24, SP
    MOVQ    BP, 16(SP)
    LEAQ    16(SP), BP
    LEAQ    type."".Person(SB), AX
    MOVQ    AX, (SP)
    PCDATA  $1, $0
    CALL    runtime.newobject(SB)
    MOVQ    8(SP), AX
    MOVQ    "".b+32(SP), CX
    MOVQ    CX, (AX)
    MOVQ    "".c+40(SP), CX
    MOVQ    CX, 8(AX)
    PCDATA  $0, $-2
    CMPL    runtime.writeBarrier(SB), $0
    JNE     foo_pc101
    MOVQ    AX, "".globalBob(SB)
 foo_pc83:
    PCDATA  $0, $-1
    MOVQ    (AX), AX
    MOVQ    AX, "".~r2+48(SP)
    MOVQ    16(SP), BP
    ADDQ    $24, SP
    RET

Que, como puedes ver, invoca newobject.


Estos listados de desmontaje fueron generados por https://godbolt.org/ , y son para ir 1.16 en AMD64

3
Eli Bendersky 9 jun. 2021 a las 00:21

Si la memoria se asigna en la pila o "escapes" al montón depende totalmente de cómo use la memoria, no sobre cómo declare la variable.

Si devuelve un puntero a una variable asignada de pila en, por ejemplo, c, el valor que su puntero no será válido cuando intente usarlo. Esto no es posible, porque no puede decir explícitamente ir a dónde colocar una variable. Hace un muy buen trabajo de elegir el lugar correcto, y si ve que las referencias a una mancha de memoria pueden vivir más allá del marco de la pila, se asegurará de que la asignación ocurra en el montón.

¿Puede Golang asignar memoria con tal notación?

var bob * Person = & Person {2, 3}

O siempre el puntero apuntará a la pila

Esa línea de código no puede ser , "Siempre" apunta a la pila, pero a veces podría, por lo que sí, es MAYOR asignar memoria (en el montón).

Nuevamente, no se trata de esa línea de código, se trata de lo que viene después de eso. Si se devuelve el valor de bob (la dirección del objeto Person), no se puede asignar en la pila porque la dirección devuelta apuntará a la memoria recuperada.

1
meager 9 jun. 2021 a las 00:25

Ponga simplemente, si el compilador puede ser , demuestre que el valor puede crearse de forma segura en la pila, se creará (probablemente) en la pila. De lo contrario, se asignará en el montón.

Las herramientas que el compilador tiene que hacer estas pruebas es bastante bueno, pero no lo hace bien todo el tiempo. Sin embargo, la mayoría de las veces, el costo vs se beneficia de preocuparse por ello no es realmente beneficioso.

0
Hymns For Disco 9 jun. 2021 a las 00:31