Maison > développement back-end > Golang > Qu'est-ce qui s'échappe dans le tas ?

Qu'est-ce qui s'échappe dans le tas ?

王林
Libérer: 2024-02-06 10:09:07
avant
1327 Les gens l'ont consulté

Quest-ce qui séchappe dans le tas ?

Contenu de la question

J'ai ce code qui est censé ne pas être alloué du tout, mais pour une raison quelconque, c'est le cas. Comme le dit le benchmark, 2 allocations ont lieu par opération.

Quelles lignes de la fonction sont allouées ? Pourquoi?

Caractéristiques :

func (vi *VarInt /* int32 */) Read(input io.Reader) error {
    var (
        b     byte
        buf   = unsafe.Slice(&b, 1)
        shift int
        value uint32
    )
    for {
        _, err := io.ReadFull(input, buf)
        if err != nil {
            return err
        }

        value |= (uint32(b) & 0b01111111) << shift

        if (b & 0b10000000) == 0 {
            *vi = VarInt(value)
            return nil
        }

        shift += 7
        if shift >= 32 {
            return ErrVarIntTooLong
        }
    }
}

func (vi *VarInt /* int32 */) Write(output io.Writer) error {
    var (
        varint [5]byte
        uvalue = uint32(*vi)
        x      int
    )
    for ; ; x++ {
        vb := uint8(uvalue)

        if (vb & 0b10000000) == 0 {
            varint[x] = vb
            break
        }

        varint[x] = (vb & 0b01111111) | 0b10000000

        uvalue >>= 7
    }

    _, err := output.Write(varint[:x+1])
    if err != nil {
        return err
    }

    return nil
}
Copier après la connexion

Référence :

func BenchmarkVarInt(b *testing.B) {
    var buf bytes.Buffer
    buf.Grow(5)
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        vi := (VarInt)(i)
        vi.Write(&buf)
        vi.Read(&buf)
        buf.Reset()
    }
}
Copier après la connexion

Je voulais buf 切片以某种方式逃逸,但我不知道如何逃逸,因为据我了解,在这种情况下切片是在堆栈上分配的结构,它将指向变量 b 作为其数据。我尝试将表达式 unsafe.Slice(&b, 1) 更改为 (*[1]byte)(unsafe.Pointer(&b))[:] mais ça n’a rien changé.


Réponse correcte


Lorsqu'une valeur est encadrée dans une interface, elle est toujours considérée comme pouvant être évacuée - même si la valeur n'est jamais utilisée en dehors de la pile d'appels, Go arrêtera d'analyser à ce stade et pensera que quelqu'un aurait pu la récupérer de l'adresse, la valeur doit être placée sur le tas.

Depuis Read 采用 io.ReaderWrite 采用 io.Writer,因此 buf (这是传递给这两个函数的 bytes.Buffer ) doit être échappé.

Même si vous faites en sorte que ces fonctions prennent des types concrets bytes.Buffer (您可能不想要),但这还不够,因为 Read 调用 io.ReadFull ,它再次采用 io.Reader . Vous devez travailler plus dur que cela pour obtenir cette dispense.

En passant, pour Read 中的其他问题,有一个更简单的解决方案,不需要任何 unsafe.Slice 恶作剧:只需将 var b byte 替换为 var b [1]byte (这正是 内存中相同),将b[:]传递给ReadFull,并在其他使用b的地方使用b[0].

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal