over-golang/08-Go运行时/01-内存分区.md
2021-07-02 18:11:59 +08:00

3.9 KiB
Raw Permalink Blame History

零 前置知识

操作系统的每个进程都认为自己可以访问计算机的所有物理内存,但由于计算机必定运行着多个程序,每个进程都不能拥有全部内存。

为了避免了进程直接访问实际的物理地址操作系统会将物理内存虚拟为一个数组每个元素都有一个唯一的物理地址PA。 物理存储其器中存储着一个页表page table该表即虚拟地址与物理地址的映射表读取该也表即可完成地址翻译。

假设一个程序访问地址为0x1001的内存实际上该数据并不一定是存储在0x1001的物理地址中甚至也不在物理内存中如果物理内存满了则可以转移到磁盘上。这些地址不必反映真实的物理地址可以称为“虚拟内存”。

一 内存分区

1.0 程序的内存使用

现在使用命令来查看Go程序的内存使用

go build main.go
size main

此时会显示Go程序在未启动时内存的使用情况

此时可执行程序内部已经分好了三段信息,分别为:

  • text 代码区
  • data 数据区
  • bss 未初始化数据区

贴士: data和bss区域可以一起称呼为静态区/全局区

  • 上述三个区域大小都是固定的

程序在执行后,会额外增加栈区、堆区。

1.1 text 代码区

代码区用于存放CPU执行的机器指令一般情况下代码区具备以下特性

  • 共享:即可以提供给其他程序调用,这样就可以让代码区的数据在内存中只存放一份即可,有效节省空间。
  • 只读:用于放置程序修改其指令
  • 规划局部变量信息

1.2 data 数据区

数据区用于存储数据:

  • 被初始化后的全局变量
  • 被初始化后的静态变量(包含全局静态变量、局部静态变量)
  • 常量数据(如字符串常量)

1.3 bss 未初始化数据区

未初始化数据区用于存储:

  • 全局未初始化变量
  • 未初始化静态变量

如果是C语言未初始化却被使用了这会产生一个随机的值。Go语言中为了防止C的这种现象该区域的数据会在程序执行之前被初始化为零值0或者空

1.4 stack 栈区

栈是一种先进后出FILO的内存结构由编译器自动进行分配和释放。一般用于存储函数的参数值、返回值、局部变量等。栈区大小一般只有1M也可以实现扩充

  • Windows最大可以扩充为10M
  • Linux最大可以扩充为16M

1.5 heap 堆区

栈的内存空间非常小,当我们遇到一些大文件读取时,栈区是不够存储的,这时候就会用到堆区。堆区空间比较大,其大小与计算机硬件的内存大小有关。

堆区没有栈的先进后出的规则位于BSS区域栈区之间用于内存的动态分配。

在C、C++等语言中该部分内存由程序员手动分配c中的malloc函数c++中的new函数和释放C中的free函数C++的delete函数如果不释放可能会造成内存泄露但是程序结束时操作系统会进行回收。

在Java、Go、JavaScript中都有垃圾回收机制(GC),可以实现内存的自动释放!

注意Go语言与其他语言不同对栈区、堆区进行虚拟管理。

1.6 操作系统内存分配图

操作系统会为每个进程分配一定的内存地址空间,如图所示:

上图所示的是32位系统中虚拟内存的分配方式不同系统分配的虚拟内存是不同的但是其数据所占区域的比例是相同的

  • 32位最大内存地址为232这么多的字节数换算为G单位即为4G。换算为1G=1024MB=10241024KB=10241024*1024B
  • 64位最大内存地址为264这么多的字节数换算为G单位数值过大不便图示

注意:栈区是从高地址往低地址存储的