如何理解Go指针和内存分配关系_Go Pointer内存Model解析
技术百科
P粉602998670
发布时间:2026-01-01
浏览: 次 Go指针变量分配位置取决于作用域和逃逸分析,而非指针本身;其指向的数据位置由创建方式决定;逃逸分析是编译期自动判断变量是否需堆分配的关键机制。
Go指针本身不特殊,它就是一个存地址的变量,大小固定(64位系统是8字节),分配位置取决于作用域和逃逸分析,而不是“因为是指针所以放堆上”。真正影响性能和行为的,是它指向的数据在哪、生命周期多长。
指针变量存在哪?看作用域和逃逸
指针变量和其他变量一样,遵循Go统一的内存分配规则:
- 函数内声明的局部指针,比如 var p *int,只要没被返回、没存进全局变量或堆对象,就分配在栈上
- 一旦编译器发现这个指针的值(即它指向的地址)会被函数外使用,比如 return &x,那 x 就会逃逸到堆,p 本身也可能被移到堆上(取决于是否被外部引用)
- 包级指针变量(如 var globalP *string)直接放在
数据段,属于静态区,程序启动时就存在,结束时才释放
指针指向的数据在哪?看创建方式
指针的值是地址,这个地址指向的内容,由创建它的方式决定:
- &x:x 本身在哪,地址就指向哪。x 在栈 → 指向栈;x 因逃逸在堆 → 指向堆
- new(T) 或 &T{}:明确在堆上分配内存,返回的指针一定指向堆
- 切片/Map/Channel 的元素地址:底层数据总在堆上,所以取到的指针也指向堆
- 栈上的指针完全可以指向堆数据(很常见),堆上的指针也可以指向其他堆数据(比如结构体字段是指针)
逃逸分析才是关键裁判
Go不靠程序员手动指定栈或堆,而是由编译器在编译期做逃逸分析,判断变量是否“逃出”当前作用域:
- 如果一个局部变量的地址被返回、赋给全局变量、传入 goroutine 或存进 map/slice,它就必须堆分配
- 命令 go build -gcflags="-m -l" 可以查看逃逸详情,比如 “moved to heap” 或 “escapes to heap”
- 逃逸不是坏事,是安全机制:避免函数返回后访问已销毁的栈内存
值类型 vs 指针类型:别只看大小
选值传递还是指针传递,不能只看结构体大不大:
- 小结构体(如两个 int 字段)值传递开销极小,栈上拷贝快,GC 无压力
- 大结构体用指针可避免拷贝,但每个指针本身带来 8 字节开销,且若指向堆,会增加 GC 扫描负担
- 更关键的是语义需求:需要修改原值?要实现某个接口(如 io.Writer)?方法接收者是否统一?这些常比内存数字更重要
基本上就这些。理解指针和内存的关系,核心是分清“指针变量在哪”和“它指向的数据在哪”,再把逃逸分析当作背后的自动调度员——它不动声色,但决定了大部分实际布局。
# 的是
# 就会
# 放在
# 是一个
# 才是
# 更重要
# 它就
# 是由
# go
# 对象
# 堆
# String
# int
# 值类型
# 字节
# 指针
# 接口
# 栈
# pointer
# var
# 结构体
# 作用域
# 切片
# map
# channel
# 指针类型
# 局部变量
# 全局变量
# 值传递
# 只看
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- 如何提升Golang程序I/O性能_Golang
- 如何使用Golang优化模块引入路径_Golang
- 如何解决Windows字体显示模糊的问题?(Cle
- Python文件操作优化_大文件与流处理解析【教程
- Win11怎么检查TPM2.0模块_Windows
- 如何用正则表达式精确匹配最多含一个换行符的起止片段
- php能控制zigbee模块吗_php通过串口与c
- 如何在Golang中实现并发消息队列消费者_Gol
- Linux怎么设置磁盘配额_Linux系统Quot
- GML (Geography Markup Lan
- Golang如何遍历目录文件_Golang fil
- 用lighttpd能运行php吗_lighttpd
- Win11怎么设置默认图片查看器_Windows1
- Windows10系统怎么查看CPU核心数_Win
- Go 中的 := 运算符:类型推导机制与使用边界详
- Windows笔记本无法进入睡眠模式怎么办?(电源
- Windows7怎么找回经典开始菜单_Window
- 手机php文件怎么变成mp4_安卓苹果打开php转
- Mac如何查看电池健康百分比_Mac系统信息电源检
- php8.4匿名类怎么用_php8.4匿名类创建与
- Win11怎么更改系统语言_Win11中文语言包下
- 如何在Golang中处理云原生事件_使用Event
- Win10如何更改电脑休眠时间_Windows10
- c# await 一个已经完成的Task会发生什么
- 如何用列表一次性对 DataFrame 的指定列应
- mac怎么看硬盘大小_MAC查看磁盘存储空间与文件
- c++如何使用std::bind绑定函数参数_c+
- Python爬虫项目实战教程_Scrapy抓取与存
- Win11相机打不开提示错误怎么修_相机权限开启与
- 如何使用Golang实现Web表单数据绑定_自动映
- 如何在Windows中创建新的用户账户?(标准与管
- php485函数执行慢怎么优化_php485性能提
- Win11如何卸载OneDrive_Win11卸载
- 如何使用正则表达式批量替换重复的 *- 模式为固定
- 如何使用Golang log设置日志输出格式_Go
- Win11 explorer.exe频繁崩溃_修复
- Win11如何更改任务栏颜色 Win11自定义任务
- Python网络超时处理_健壮性设计说明【指导】
- c++中如何使用std::variant_c++1
- php打包exe后无法读取环境变量_变量配置方法【
- c++怎么使用std::filesystem遍历文
- Win10怎么设置开机密码_Windows10账户
- mac怎么安装pip_MAC Python pip
- Win10电脑怎么设置网络名称_Windows10
- Go语言中slice追加操作的底层共享机制详解
- 如何在Golang中验证模块完整性_Golangg
- php文件怎么变mp4保存_php输出视频流保存为
- Win11怎么查看已连接wifi密码 Win11查
- 如何使用Golang管理模块版本_Golanggo
- Windows10电脑怎么设置文件权限_Win10

数据段,属于静态区,程序启动时就存在,结束时才释放
QQ客服