golang 内存分配器

wolf4j · · 1592 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

背景

go的很多东西是内敛的,提倡大道至简,但是,我们也看到过对于一些对性能要求比较高的业务场景(比如游戏的某些业务场景),使用cgo等技术手段来绕过go的垃圾回收。所以说,我们不要把所有的目光都盯到那95%上,依然还有5%的情况是需要我们来处理的。即便在今天来看,内存依然是非常紧缺的资源,那么我们可以想象一下,如何管理和分配内存资源,这是一个非常有挑战的话题。

下面我们来看一下这段代码,看看内存究竟发生来什么。

package main

func A() *int {
  x := 100
  return &x
}

但是如果有c语言经验的人,会知道这个代码是有问题的,我们来简单测试一下这个代码。

package main

import "testing"

func BenchmarkA (b *testing.B){
  for i := 0; i < b.N; i++{
    A()
  }
}

执行go test -v -test.bench . -benchmem之后,测试结果如下:

goos: darwin
goarch: amd64
pkg: golang/runtime
BenchmarkA-4    2000000000               0.32 ns/op            0 B/op          0 allocs/op
PASS
ok      golang/runtime  0.739s

感觉没有什么问题,只是做性能测试,那么我在不修改参数的情况下,加一个参数,禁止函数内联,我们再进行一下测试

执行go test -v -test.bench . -benchmem -gcflags -l,继续执行,测试情况如下:

goos: darwin
goarch: amd64
pkg: golang/runtime
BenchmarkA-4    100000000               15.8 ns/op             8 B/op          1 allocs/op
PASS
ok      golang/runtime  1.646s

我们可以看到性能下降的很严重,关键是,它每次执行都会在内存上进行一次
分配, 64位系统的是8字节(整数指针),很显然,go对于内存分配的这种行为是由运行时和编译器来决定的,跟我们写的代码无关,也就是当我们写下这段代码的时候,我们并不能保证我们的变量是分配在栈上还是堆上的。

应用系统可能有时候不太关心,但是我们可以想象一下,每秒钟会在内存中分配几十万个临时对象,这几十万个临时对象会对GC造成多大的压力。因为有时候垃圾回收并不在乎你这个对象是大是小,而在乎的是你这个对象有多少个,为什么?因为他需要检查你的每个对象究竟是不是可达的,他需要把所有可达对象保留下来,把所有不可达对象回收了。也就是说,在单位时间内,堆上的临时对象越多,垃圾回收的压力越大。小小的一个控制开关,会导致你的性能有很大的影响。内存在栈上分配,变成了在堆上分配。

内存分配器由来

内存单元

初始化和基本架构

内存分配

内存回收

物理内存释放



有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:wolf4j

查看原文:golang 内存分配器

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1592 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传