为什么要探究这个问题?

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

§ 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. CF1093E 题解

    来一发 \(O(n \sqrt n)\) 时间,\(O(n)\) 空间的分块写法. 首先建模,把 数值 \(x\) 在两个数组中出现的位置作为坐标,问题就转化为一个二维动态数点. 考虑用序列分块维护第 ...

  2. P9212 题解

    显然,我们维护的答案具有 可差分 性,所以转换为 \([1,r]\) 上的查询. 首先,对于 \(x,y,a_i\) 先对 \(m\) 取模不影响结果. 下面为了方便令 \(v = a_i\). 如果 ...

  3. 坚果云与floccus实现Chrome书签国内跨设备、跨平台同步

      本文介绍基于floccus插件与坚果云协同使用的方法,对浏览器的书签进行实时在线同步的操作.   在工作与学习中,我们时常希望在不同浏览器之间实现书签的同步:而一些传统的浏览器书签同步方案,或多或 ...

  4. Java 对象转XML xStream 别名的使用 附下载方式

    下载方式 Maven方式 pom.xml中 <dependency> <groupId>xstream</groupId> <artifactId>xs ...

  5. 数据存储为json或数据库

    1.数据存储 In [ ]: import requests from bs4 import BeautifulSoup rqq = requests.get('http://www.tipdm.co ...

  6. 类、事件与对象---Dad&Mom简单练习

    目的: 模拟一个家庭日常发生的场景:妈妈做好饭,说:"开饭了!",这是爸爸听到了妈妈的喊话就立马动身开始饭吃.而儿子此时正在打游戏,于是他就说:"等我打完这把游戏再吃!& ...

  7. Python 生成条形码、二维码 (Code 128、EAN-13、QR code等)

    条形码和二维码是现代信息交换和数据存储的重要工具,它们将信息以图形的形式编码,便于机器识别和数据处理,被广泛应用于物流.零售.医疗.教育等各领域.本文将介绍如何使用Python快速生成各种常见的条形码 ...

  8. [oeasy]python0050_动态类型_静态类型_编译_运行

    动态类型_静态类型 回忆上次内容 上次了解了 帮助文档的 生成 开头的三引号注释 可以生成 帮助文档 文档 可以写成网页   python3 本身 也有 在线的帮助手册   目前的程序 提高了 可读性 ...

  9. oeasy教您玩转vim - 22 - 配置文件

    配置文件 回忆上节课内容 我们上次了解到了状态横条 通过转义表示 item 控制 item 宽度的方法 将 item 成组的方法 还有一个总开关 laststatus 但是每次都要写很长的一段话来配置 ...

  10. 改善中国打开GitHub网站的速度

    您可以采取以下措施来改善您在中国打开GitHub网站的速度:1. 使用VPN:通过连接到VPN服务器,您可以避免中国政府对GitHub网站进行的封锁,从而获得更快的访问速度.2. 使用加速器:国内有很 ...