为什么要探究这个问题?

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

§ 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 $@.d -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/<pid>/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规定的,目前我们用的是汇编实现的,不需要用堆。

Go进程内存占用那些事(一)的更多相关文章

  1. Linux系统下输出某进程内存占用信息的c程序实现

    在实际工作中有时需要程序打印出某个进程的内存占用情况以作参考, 下面介绍一种通过Linux下的伪文件系统/proc 计算某进程内存占用的程序实现方法. 首先, 为什么会有所谓的 伪文件 呢. Linu ...

  2. Linux查看进程内存占用及内存使用情况

    LINUX进程内存占用查看方法(1)top可以直接使用top命令后,查看%MEM的内容.可以选择按进程查看或者按用户查看,如想查看oracle用户的进程内存使用情况的话可以使用如下的命令:$ top ...

  3. 监控Linux系统所选的服务所占进程内存占用

    [代码] #!/bin/bash #程序功能描述: # 监控系统所选的服务所占进程内存占用 #作者:孤舟点点 #版本:1.0 #创建时间:-- :: PATH=/bin:/sbin:/usr/bin: ...

  4. window 实用操作(结束已打开无法删除进程 内存占用)

    1.win7删除文件,文件夹或文件已在另一程序中打开:https://jingyan.baidu.com/article/e75057f2a41e88ebc91a8985.html 删除文件时,提示“ ...

  5. 查看LINUX进程内存占用情况

    可以直接使用top命令后,查看%MEM的内容.可以选择按进程查看或者按用户查看,如想查看oracle用户的进程内存使用情况的话可以使用如下的命令: (1)top top命令是Linux下常用的性能分析 ...

  6. 查看LINUX进程内存占用情况(转)

    可以直接使用top命令后,查看%MEM的内容.可以选择按进程查看或者按用户查看,如想查看oracle用户的进程内存使用情况的话可以使用如下的命令: (1)top top命令是Linux下常用的性能分析 ...

  7. 查看LINUX进程内存占用情况及启动时间

    可以直接使用top命令后,查看%MEM的内容.可以选择按进程查看或者按用户查看,如想查看oracle用户的进程内存使用情况的话可以使用如下的命令: (1) top top命令是Linux下常用的性能分 ...

  8. linux 查看某个进程内存占用情况命令

    1.先用ps查询进程号 ps -aux|grep 进程名字 2.查看更详细的内存占比 cat /proc/3664/status 返回结果:(其中VmRSS为进程所占用的内存)

  9. linux查看进程内存占用

    ps -aux | grep xxx USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND 可以看到RSS ...

  10. 使用showmap分析android进程内存占用情况(转载)

    转自:http://my.oschina.net/shaorongjie/blog/105354 可以使用adb shell showmap pid查看一个进程的showmap,这对于我们来说非常有用 ...

随机推荐

  1. Android7.0 配置JACK支持多用户同时编译

    # Android7.0 配置JACK支持多用户同时编译 reference: https://blog.csdn.net/whorus1/article/details/80364772 https ...

  2. 浅谈k8s中cni0和docker0的关系和区别

    最近在复习k8s网络方面的知识,查看之前学习时整理的笔记和文档还有过往自己总结的博客之后发现一个问题,就是在有关flannel和calico这两个k8s网络插件的文章和博客中,会涉及到cni0和doc ...

  3. 【论文阅读】IROS2021: PILOT: Efficient Planning by Imitation Learning and Optimisation for Safe Autonomous Driving

    参考与前言 完整题目:PILOT: Efficient Planning by Imitation Learning and Optimisation for Safe Autonomous Driv ...

  4. 计算订单签收率的sql查询思路与过程(涉及百分比和四舍五入)

    领导提出一个签收率需求,想要通过数据库达到excel中表现的形式,提高计算速度和工作效率, 如下形式: 数据库中表数据结构: 部分数据如下: sql语句思路如下: -- 1.已签收:以物流反馈管道,状 ...

  5. CentOS中增加网络连接数的方法

    CentOS默认对外访问,发起的TCP链接总数小于28232个. 可以通过以下命令的结果计算出来 $ cat /proc/sys/net/ipv4/ip_local_port_range 我这里得到的 ...

  6. SDL3 入门(5):纹理渲染

    创建纹理 有三个 API 可以用来创建纹理: SDL_CreateTexture 参数少,使用方便,适用于创建简单的纹理 SDL_CreateTextureFromSurface 适用于从已有图像数据 ...

  7. 毕设项目:springboot+vue实现的在线求职平台

    一.前言 随着信息技术的飞速发展和互联网的普及,线上求职已成为众多求职者和企业招聘的重要渠道.为满足市场需求,我们利用Spring Boot和Vue技术栈,开发了一款功能全面.用户友好的在线求职平台. ...

  8. 题解:CF1918B Minimize Inversions

    CF1918B Minimize Inversions 思路 暴力 一个一个的算,复杂度巨大. 数学规律 让逆序最少,也就是让升序更多.我们可以通过多组数据实验,最终我们会发现,将数列 \(A\) 减 ...

  9. 在 Hub 上使用 Presidio 进行自动 PII 检测实验

    我们在 Hugging Face Hub 上托管的机器学习 (ML) 数据集中发现了一个引人关注的现象: 包含个人未经记录的私密信息.这一现象为机器学习从业者带来了一些特殊挑战. 在本篇博客中,我们将 ...

  10. 11、Git之自建项目托管平台(GitLab极狐)

    11.1.简介 Github 是国外的项目托管平台,由于网络问题,在国内访问和使用不是很方便. Gitee 是国内的项目托管平台,虽然在访问和使用上挺方便的,但依然让人担忧项目代码可能会被泄露. 因此 ...