[Golang] Go efficient use of pointer

Go pointer in two ways, one is UIntPtr built-in type, is essentially an integer, and the other is provided Pointer unsafe packet indicating pointer can point to any type. Uintptr typically used to calculate a pointer, since it is an integer, it is easy to calculate the position of a pointer points to the next, and unsafe.Pointer used for bridging, for different types of pointers each conversion.

Go unsafe.Pointer and also provides some guidelines uintptr use.

With these basic concepts, how can we play?

Usually we will byte [] is converted to a string of doing so:

b := byte[]("Peppa")
string(b)

This way there is a problem that will allocate memory and copy a more efficient way should not allocate any memory, type conversion in the original memory.

is essentially a slice structure, which contains a pointer pointing to the underlying array and Len, Cap members, can be seen through the slice reflect package is represented by:

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

Data which is a pointer to the first element of the underlying array. The reason why the byte slice can be converted into the original string in the string because the memory is more like the structure and slice, reflect package can be seen through this string is represented by:

type StringHeader struct {
    Data uintptr
    Len  int
}

So we just constructed StringHeader on it on the original memory.

sh := reflect.StringHeader{
    uintptr(unsafe.Pointer(&b[0])),
    len(b),
}

Data points which is the first element of the slice, Len length of the slice. As used herein unsafe.Pointer been bridged.
StringHeader created objects, the next step is to convert it into an object of type string, how to do it? Or bridged by unsafe.Pointer.

*(*string)(unsafe.Pointer(&sh))

StringHeader first type pointer to unsafe.Pointer conversion, and then converted into unsafe.Pointer string pointer type, a value finally obtained by the actual pointer value.
This type of conversion is by way unsafe.Pointer in unsafe package also described, wherein the examples given is the math package Float64bits Method:

func Float64bits(f float64) uint64 {
    return *(*uint64)(unsafe.Pointer(&f))
}

We can verify whether two ways to re-allocate the memory.

import (
    "github.com/davecgh/go-spew/spew"
    "unsafe"
    "reflect"
    "fmt"
)

func byteToString(b []byte) string {
    return string(b)
}

func byteToStringNoAlloc(b []byte) string {
    if len(v) == 0 {return ""}
    sh := reflect.StringHeader{uintptr(unsafe.Pointer(&b[0])), len(b)}
    return *(*string)(unsafe.Pointer(&sh))
}

func main() {
    b := []byte("Peppa")
    fmt.Println("切片第一个元素: ", spew.Sdump(&b[0]))

    str := byteToString(b)
    sh := (*reflect.StringHeader)(unsafe.Pointer(&str))
    fmt.Println("分配内存的方式: ", spew.Sdump(sh))

    strNoAlloc := byteToStringNoAlloc(b)
    shNoAlloc := (*reflect.StringHeader)(unsafe.Pointer(&toStr))
    fmt.Println("不分配内存的方式: ", spew.Sdump(shNoAlloc))
}

Here Insert Picture Description
This will give rise to a more serious problem, Data at the memory may at any time be recycled because uintptr is unsafe, so when that part of the memory is recovered, which may be converted to operate on the original memory lead to panic, so in this way to be vigilant.

unsafe package also provides secure stringHeader and sliceHeader, but they are not exposed, so had no way to avoid the memory is not being recycled cast.

Published 360 original articles · won praise 14 · Views 100,000 +

Guess you like

Origin blog.csdn.net/LU_ZHAO/article/details/105332760