mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-20 12:44:20 +08:00
fix typo
This commit is contained in:
@@ -42,7 +42,7 @@ pb := (*int16)(unsafe.Pointer(tmp))
|
||||
*pb = 42
|
||||
```
|
||||
|
||||
产生错误的原因很微妙。有时候垃圾回收器会移动一些变量以降低内存碎片等问题。这类垃圾回收器被称为移动GC。当一个变量被移动,所有的保存改变量旧地址的指针必须同时被更新为变量移动后的新地址。从垃圾收集器的视角来看,一个unsafe.Pointer是一个指向变量的指针,因此当变量被移动是对应的指针也必须被更新;但是uintptr类型的临时变量只是一个普通的数字,所以其值不应该被改变。上面错误的代码因为引入一个非指针的临时变量tmp,导致垃圾收集器无法正确识别这个是一个指向变量x的指针。当第二个语句执行时,变量x可能已经被转移,这时候临时变量tmp也就不再是现在的`&x.b`地址。第三个向之前无效地址空间的赋值语句将彻底摧毁整个程序!
|
||||
产生错误的原因很微妙。有时候垃圾回收器会移动一些变量以降低内存碎片等问题。这类垃圾回收器被称为移动GC。当一个变量被移动,所有的保存该变量旧地址的指针必须同时被更新为变量移动后的新地址。从垃圾收集器的视角来看,一个unsafe.Pointer是一个指向变量的指针,因此当变量被移动时对应的指针也必须被更新;但是uintptr类型的临时变量只是一个普通的数字,所以其值不应该被改变。上面错误的代码因为引入一个非指针的临时变量tmp,导致垃圾收集器无法正确识别这个是一个指向变量x的指针。当第二个语句执行时,变量x可能已经被转移,这时候临时变量tmp也就不再是现在的`&x.b`地址。第三个向之前无效地址空间的赋值语句将彻底摧毁整个程序!
|
||||
|
||||
还有很多类似原因导致的错误。例如这条语句:
|
||||
|
||||
@@ -52,7 +52,7 @@ pT := uintptr(unsafe.Pointer(new(T))) // 提示: 错误!
|
||||
|
||||
这里并没有指针引用`new`新创建的变量,因此该语句执行完成之后,垃圾收集器有权马上回收其内存空间,所以返回的pT将是无效的地址。
|
||||
|
||||
虽然目前的Go语言实现还没有使用移动GC(译注:未来可能实现),但这不该是编写错误代码侥幸的理由:当前的Go语言实现已经有移动变量的场景。在5.2节我们提到goroutine的栈是根据需要动态增长的。当发送栈动态增长的时候,原来栈中的所以变量可能需要被移动到新的更大的栈中,所以我们并不能确保变量的地址在整个使用周期内是不变的。
|
||||
虽然目前的Go语言实现还没有使用移动GC(译注:未来可能实现),但这不该是编写错误代码侥幸的理由:当前的Go语言实现已经有移动变量的场景。在5.2节我们提到goroutine的栈是根据需要动态增长的。当发生栈动态增长的时候,原来栈中的所有变量可能需要被移动到新的更大的栈中,所以我们并不能确保变量的地址在整个使用周期内是不变的。
|
||||
|
||||
在编写本文时,还没有清晰的原则来指引Go程序员,什么样的unsafe.Pointer和uintptr的转换是不安全的(参考 [Issue7192](https://github.com/golang/go/issues/7192) ). 译注: 该问题已经关闭),因此我们强烈建议按照最坏的方式处理。将所有包含变量地址的uintptr类型变量当作BUG处理,同时减少不必要的unsafe.Pointer类型到uintptr类型的转换。在第一个例子中,有三个转换——字段偏移量到uintptr的转换和转回unsafe.Pointer类型的操作——所有的转换全在一个表达式完成。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user