Writing memory-safe code in Go is critical to prevent program crashes, data corruption, and security vulnerabilities. Practices include: passing pointers, using slice capacity, avoiding buffer overflows, using slices with caution, using make() to create slices and maps, using defer to release resources, and using sync.Mutex to synchronize concurrent access. Following these practices can improve the robustness and reliability of your code and be reflected in practical cases.
Writing memory-safe code in Go is critical to prevent program crashes, data corruption, and security vulnerabilities. Following the following practices can help improve the robustness and reliability of your code.
Passing a pointer (*T
) instead of a value (T
) prevents accidental modification of the passed-in value. For example:
func Swap(a, b *int) { *a, *b = *b, *a }
Slices ([]T
) are based on the underlying array, so understanding its capacity is crucial. Capacity represents the maximum length of the array. When capacity is exceeded, Go will automatically allocate a larger underlying array, thus changing the address of the slice.
The following code demonstrates this:
s := []int{1, 2, 3} println(len(s), cap(s)) // 3 3 s = append(s, 4) println(len(s), cap(s)) // 4 6
A buffer overflow occurs when the amount of data stored exceeds the buffer allocated to it. In Go, you can avoid this situation using the following methods:
copy()
Function: copy()
Ensure that the amount of copied data does not exceed the capacity of the target buffer. Slices are not memory-safe types because they share the underlying array. Modifications to a slice may unexpectedly affect other variables that use the same array.
The following example illustrates this:
s1 := []int{1, 2, 3} s2 := s1[1:] s1[0] = 4 println(s1) // [4 2 3] println(s2) // [2 3]
make()
Explicitly creating slices and maps lets you specify their initial capacity and avoid unnecessary allocations. Use
statement ensures that a block of code is executed before the function returns. This is useful for freeing resources such as open files or network connections. The following example uses
to close the file: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:go;toolbar:false;'>func main() {
file, err := os.Open("file.txt")
if err != nil {
return
}
defer file.Close()
// 执行其他操作
}</pre><div class="contentsignin">Copy after login</div></div>
Using
is a mutex lock used to synchronize concurrent access to shared resources. Mutex
You can acquire and release locks through the Lock()
and Unlock()
methods. The following example uses
to protect concurrent access to shared data: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:go;toolbar:false;'>var mu sync.Mutex
var count int
func main() {
for i := 0; i < 10; i++ {
go func() {
mu.Lock()
defer mu.Unlock()
count++
}()
}
// 等待所有协程完成
}</pre><div class="contentsignin">Copy after login</div></div>
Practical case
func Intersection(s1, s2 []int) []int { var res []int for _, v1 := range s1 { for _, v2 := range s2 { if v1 == v2 { res = append(res, v1) } } } return res }
We can improve the memory safety of this function by following the following principles:
Use slice capacity to avoid unnecessary allocations.
Use
func Intersection(s1, s2 []int) []int { res := make([]int, 0, min(len(s1), len(s2))) for _, v1 := range s1 { for _, v2 := range s2 { if v1 == v2 { copy(res[len(res):], []int{v1}) } } } return res }
Following these practices helps to write memory-safe Go functions and improve the robustness, reliability and security of the code.
The above is the detailed content of Golang function memory safety programming practice. For more information, please follow other related articles on the PHP Chinese website!