go - 全局变量地址
问题描述
我只是在玩 Go 接口和结构,突然发现一些奇怪的东西。情况是这样的:
https://play.golang.org/p/FgvRFV9Lij9
package main
import (
"fmt"
)
func main() {
scopedInt := 100
fmt.Printf("%p\n", &scopedInt)
globalInt = 100
fmt.Printf("%p\n", &globalInt)
}
var globalInt int
输出:
0xc0000ba010
0x57b2a8
地址的值无关紧要。关键是为什么第一个地址的位数比第二个多?
我想我错过了关于 Go 中全局变量概念的一点。
解决方案
地址的“长度”相差很多位数,因为这些变量分配在内存的不同区域,这些区域具有不同的偏移量(起始位置)。
scopedInt
可能会在堆上分配,因为它从main()
(其地址传递到fmt.Printf()
)“逃逸”,而globalInt
它是一个包级变量,因此将分配在固定大小的段之一,即数据段中。
只要地址指向有效的内存区域,地址的“长度”就无关紧要。Go 具有自动内存管理功能,因此除非您触摸 package unsafe
,否则您不必担心地址和指针是否有效。
要了解有关内存管理的更多信息,请参阅Doug Richardson:Go Memory Management。引用它:
什么去哪里?
Go 编程语言规范没有定义项目的分配位置。例如,定义为的变量
var x int
可以分配在堆栈或堆上,并且仍然遵循语言规范。p
同样, in指向的整数p := new(int)
可以分配在堆栈或堆上。但是,某些要求将在某些条件下排除某些内存选择。例如:
- 数据段的大小在运行时不能改变,因此不能用于改变大小的数据结构。
- 堆栈中项目的生命周期按它们在堆栈中的位置排序。如果堆栈的顶部是地址 X,那么 X 之上的所有内容都将被释放,而 X 之下的所有内容都将保持分配状态。如果被函数范围之外的项目引用,函数分配的内存可以转义该函数,因此不能在堆栈上分配(因为它仍在被引用),也不能在数据段中分配(因为数据段不能在运行时增长),因此它必须在堆上分配——尽管内联可以删除其中一些堆分配。
推荐阅读
- java - 元素的自定义适配器视图持有者位置
- database - 您将如何对数据库进行建模以存储可以以分层方式使用的配置
- java - 不知道如何通过 findByRole 返回自定义的用户列表
- laravel - Laravel 通知将一个通知标记为已读
- javascript - JavaScript:忽略特定页面上 script.js 中的函数
- angularjs - 如何为angularjs数组中的每个元素创建一个唯一的超链接
- python - 如何使用python从POST请求中获取查询参数
- python - 如何删除我的 plyer 通知功能中的“Python”文本?
- mysql - 如何解决 ERROR 1452 使用 mysql 在表中添加外键
- gradle - 不能运行多个 LibGDX 游戏