Content #
参与 for range 循环的是 range 表达式的副本 #
我们来看一个简单的例子:
func main() {
var a = [5]int{1, 2, 3, 4, 5}
var r [5]int
fmt.Println("original a =", a)
for i, v := range a {
if i == 0 {
a[1] = 12
a[2] = 13
}
r[i] = v
}
fmt.Println("after for range loop, r =", r)
fmt.Println("after for range loop, a =", a)
}
我们期望这个程序会输出如下结果:
original a = [1 2 3 4 5]
after for range loop, r = [1 12 13 4 5]
after for range loop, a = [1 12 13 4 5]
但实际运行该程序的输出结果却是:
...
通过上图我们可以看出,第 46 和 47 位是预留的,也就是说标记位可以继续向左移两位,那么可以支持的堆空间就可以扩展到 16T。当前很多资料说 ZGC 只支持 4T 内存,实际上现在最新版本已经支持到了 16T。
上图中,对象 a 和对象 b 都引用了对象 foo,当 foo 正在拷贝的过程中,应用线程 A 可以访问旧的对象 foo 得到正确的结果,当 foo 拷贝完成之后,应用线程 B 就可以通过 read barrier 来获取对象 foo 的新地址,然后直接访问对象 foo 的新地址。
三个周期(Cycle)之间的关系