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

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

王林
王林avant
2024-02-06 10:09:071231parcourir

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
}

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()
    }
}

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:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer