首页 > 系统相关 >Go进程内存占用那些事(一)

Go进程内存占用那些事(一)

时间:2024-02-01 14:57:53浏览次数:33  
标签:4KiB demo 占用 内存 Go section 加载

为什么要探究这个问题?

作为基础设施供应商,自己的服务占用多少内存,为什么要占用这么多内存,需要能说的清楚。作为一个云计算开发,这点问题都弄不清楚,说不过去。

§ 0x01 范围

讨论的只限于Linux X86平台下,因为实用第一。内存页大小为4KiB。

目标:说清楚一个大型的Go进程内存消耗在了哪里。

Go具有自己的运行时,其内存构成比较复杂。想说清楚和容易理解,有些难度。先从较简单的C程序说起。

§ 0x02 先说普通的C程序

正常能写出的最简单的程序,没有任何依赖,当然用汇编写出来的。个人更喜欢AT&T风格的,如下:

.section .data
.section .text
.globl _start
_start:
movl $1, %eax
movl $5, %ebx
int $0x80

写个Makefile。

all: demo

demo: demo.o
    # ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o [email protected] -lc $<
    ld -static --no-dynamic-linker -o $@ -lc $<

demo.o: demo.s
    as -gstabs  -o $@ $<

clean:
    rm ./demo ./demo.o

简单说明下过程,通过as编译,然后通过ld进行链接,最终生成一个static link的二进制。它不依赖libc,在Linux下能做到的最小程序。

需要安装gcc和gas等组件。执行make后,生成一个demo的二进制。运行这个二进制,只有一个系统调用就是设置退出码。执行一下,并没有任何输出,因为它只设置了一个退出码。可以通过 echo $?进行确认。想进一步实验,可以改成别的退出码。

$ ./demo; echo $?
5

使用gdb调试下这个程序让它暂停住,看下它的内存占用。

ulin      7116  0.0  0.0    168    24 pts/13   t    09:17   0:00 /mnt/d/code/lean/go-memory/asm/demo

它的RSS值是24,单位是KiB,也就是说它个最小程序的内存占用是24KiB。

下面我们来探究下为什么最小的程序也会占用24KiB内存。进程是由二进制加载到内存中形成的,所以起点还是看二进制,也就是elf的组成。

通过readelf -S看到各段大小如下:

section size(B) 说明
NULL 0 elf中规定的空置段,占了4KiB
.text 代码段 12 大小只有12B,但对齐后16B
.symtab 符号表 144 可以通过strip去除
.strtab 字符串表 25
.shstrtab 33

elf的布局如下:
通过readelf -a -W demo获取。

1. ELF header
2. Program header
3. sections
4. section Header table
区段 偏移 大小
ELF header 0 64
Program header 64 56 * 2 = 112
sections 176 4096 + 16 + 144 + 25 = 4281
section header table 4320 5 * 64 = 320

上各section中,只有.text和会加载到内存中。代码段只有12B,为什么进程的RSS是24KiB。

/proc/7768/smaps中有记载详细的内存布局,demo的具体内容摘要如下。先说下Pss与Rss的区别。

Rss是实际段大小,Pss是私有段大小。如果是一个.so文件,有其他进程共享,则Pss=Rss/N。实际占用的是所有段的Pss值之和。

Pss值 说明
00400000-00401000 4KiB 根据 Program Header看,应该是NULL段加载进来的。只读。
00401000-00402000 4KiB 代码段,rxp,可执行。根据 Program Header加载的。
7ffff7ff9000-7ffff7ffd000 4KiB 看注释应该是环境变量。只读。
7ffff7ffd000-7ffff7fff000 4KiB vdso段,内核映射的伪so。
7ffffffdd000-7ffffffff000 8KiB

刚好是24KiB大小。因为内存页的属性是按照最小单页的粒度,所以代码段不足4KiB,但也分配了4KiB。

§ 0x03 小结

我们探讨了最小C程序的内存占用,将其RSS的组成分析清楚了。整体的结论如下:

  1. elf中的部分section会映射到进程的内存中。
  2. 进程中最终的内存section由两种来源:
  • 在Program Header中告诉加载器,把哪些字段加载到内存中,并设置对应的Flag。
  • 加载器自己规定的共用的一些段,如vdso、栈、环境变量段。

疑问:为什么没有看到堆段(即heap)呢?猜测那是glibc规定的,目前我们用的是汇编实现的,不需要用堆。

标签:4KiB,demo,占用,内存,Go,section,加载
From: https://www.cnblogs.com/linlinsite/p/18001197

相关文章

  • Mac 安装goland2023.3
    DataGrip/Goland相关工具链接:https://pan.baidu.com/s/1UTSusTKPPnIqxdKCAi1oKg提取码:9wej对应的激活码此处获取:https://docs.qq.com/doc/DZWFmak1WcVBhdENumac使用命令shxxx.sh执行如果原来有安装goland的话,需要先卸载干净访达中在资源库中清除......
  • google play(谷歌) 订阅接入 支付后台配置
    一、Google开发者平台配置回调订阅后台地址https://console.cloud.google.com/projectselector2/cloudpubsub/topic/list 新建主题   创建订阅输入回调服务端地址(付款成功后进行回调) 并且需要设置 [email protected]......
  • go build 国内 失败
    *[Go国内加速:Go国内加速镜像|Go技术论坛](https://learnku.com/go/wikis/38122) *[SECURITYERRORThisdownloaddoesNOTmatchanearlierdownloadrecordedingo.sum.Thebitsmayhavebeenreplacedontheoriginserver,oranattackermayhaveintercepte......
  • 07django
    聚合查询MySQL聚合函数:max\min\sum\count\avgfromdjango.db.modelsimportMax,Min,Sum,Avg,Countres=models.Book.objects.aggregate(Max('price'))#总计print(res)#{'price__max':Decimal('56777.98')}'''没有分组也可......
  • Linux下查询CPU,内存,磁盘及操作系统
    查询CPU核数nproc结果为4查询内存free-h#以人类(human)可读的方式展示结果为totalusedfreesharedbuff/cacheavailableMem:15Gi2.2Gi327Mi1.0Mi13Gi13GiSwap:......
  • 内存是如何工作的
    一、什么是内存从外观上辨识,它就是内存条;从硬件上讲,它叫RAM,翻译过来叫随机存储器。英文全称:RandomAccessMemory。它也叫主存,是与CPU直接交换数据的内部存储器。其特点是读写速度快,不是一般的快,是我们想像不到的快。我们可以把内存想像成小时候写作文的本子,只不过,内存的每一行数据......
  • Go官方放出泛型slices包
    阅读本文大概需要6分钟。slices 标准库是Go1.21新增的一个包,它提供了许多对切片(slices)进行常见操作的泛型函数,可以适用于任何元素类型的切片。切片是Go语言中一种重要的数据结构,它可以动态地存储和管理一组相同类型的元素。切片的底层实现是一个数组,但是切片可以根据需要......
  • golang 正则过滤sql注入的方法
    该方法返回的是一个bool值packagemainimport"regexp"import"fmt"//正则过滤sql注入的方法//参数:要匹配的语句funcFilteredSQLInject(to_match_strstring)bool{//过滤‘//ORACLE注解--/**///关键字过滤update,delete//正则的字符......
  • 谷歌学术指标(Google Scholar Metrics)
    影响因子(ImpactFactor,IF)是上世纪由汤森路透公司开发的,最初主要用途是为科研机构和图书馆选购期刊提供参考,现在被广泛用于衡量期刊的影响力。由于IF是一个相对统计量,所以可公平地评价和处理各类期刊。通常,期刊影响因子越大,它的学术影响力和作用也越大。我们看一下IF的计算方法:IF=......
  • golang中 UTF-8 和GBK格式的转换
    funcmain(){ str:="测试" utf8By:=[]byte(str) gbkBy,_:=Utf8ToGbk(utf8By) //直接打印用string转类型的gkb字节数组,会乱码 fmt.Println("打印GBK",string(gbkBy)) fmt.Println("UTF8字节长度:",len(utf8By),"GBK字节长度:",len(gbkBy)) ......