出于很多目的,我从最新的 Go 系统内核开发源码复制了一份代码,在一个正常的运行环境中构建(和重新构建)它,在构建版本基础上周期性地重新构建 Go 程序。近期我在用 ps 查看我的一个程序的内存使用情况时,发现它占用了约 138 GB 的巨大虚拟空间(Linux ps 命令结果的 VSZ 字段),尽管它的常驻内存还不是很大。某个进程的常驻内存很小,但是需要内存很大,通常是表示有内存泄露,因此我心里一颤。

(用之前版本的 Go 构建后,根据运行时间长短不同,通常会有 32 到 128 MB 不同大小的虚拟内存占用,比最新版本小很多。)

还好这不是内存泄漏。事实上,之后的实验表明即使是个简单的 hello world 程序也会有占用很大的虚拟内存。通过查看进程的 /proc//smaps 文件((cf)可以发现几乎所有的虚拟空间是由两个不可访问的 map 占用的,一个占用了约 8 GB,另一个约 128 GB。这些 map 没有可访问权限(它们取消了读、写和可执行权限),所以它们的全部工作就是专门为地址空间预留的(甚至没有用任何实际的 RAM)。大量的地址空间。

这就是现在的 Go 在 64 位系统上的低级内存管理的工作机制。简而言之,Go (理论上)从连续的 arena 区域上进行低级内存分配,申请 8 KB 的页;哪些页可以无限申请存储在一个巨大的 bitmap。在 64 位机器上,Go 会把全部的内存地址空间预留给 bitmap 和 arena 区域本身。程序运行时,当你的 Go 程序真正使用内存时,arena bitmap 和内存 arena 片段会从简单的预留地址空间变为由 RAM 备份的内存,供其他部分使用。

(bitmap 和 arena 通常是通过给 mmap 传入 PROT_NONE 参数进行初始化的。当内存被使用时,会使用 PROT_READ|PROT_WRITE 重新映射。当释放时,我不确定它做了什么,所以对此我不发表意见。)

这个例子是用当前发布的 Go 1.4 开发版本复现的。之前的版本的 64 位程序运行时会占用更小的需要空间,虽然读 Go 1.4 源码时我也没找到原因。

以我的理解,一个有意思的影响是 64 位 Go 程序的大部分内存分配都可能占用至多 128 GB 的空间(也可能在整个运行周期内所有的内存分配都会,我不确定)。

了解更多细节,请看 src/runtime/malloc2.go 的注释和 src/runtime/malloc1.gomallocinit()

我不得不说,这个比我最初以为地更有意思也更有教育意义,尽管这意味着查看 ps 不再是一个检测你的 Go 程序中内存泄露的好方法(温馨提示,我不确定它曾经是不是)。结论是,检测这类内存使用最好的方法是同时使用 runtime.ReadMemStats()(可以通过 net/http/pprof 暴露出去)和 Linux 的 smem 程序或者养成对有意义的内存地址空间占用生成详细信息的习惯。

PS: Unix 通常足够智能,可以理解 PROT_NONE 映射不会耗尽内存,因此不应该对系统内存过量使用的限制进行统计。然而,它们会统计每一个进程的总地址空间进行统计,这意味着你运行 1.4 的 Go 程序时不能真的使用这么多。由于总内存地址空间的最大数几乎不会达到,因此这似乎不是一个问题。

附录:在 32 位系统上是怎样的

所有的信息都在 mallocinit() 注释中。简而言之,就是运行时预留了足够大的 arena 来处理 2 GB 的内存(「仅」占用 256 MB)但是仅预留 2 GB 中理论上它可以使用的 512 MB 地址空间。如果后续的运行过程中需要更多内存,就向操作系统申请另一个块的地址空间,优先 arena 区域剩下的 1.5 GB 的地址空间中分配。大多数情况下,运行的程序都会正常申请到需要分配的空间。


via: https://utcc.utoronto.ca/~cks/space/blog/programming/GoBigVirtualSize

作者:ChrisSiebenmann 译者:lxbwolf 校对:polaris1119

本文由 GCTT 原创编译,Go语言中文网 荣誉推出

为什么你的 64-bit 程序可能占用巨大的虚拟空间的更多相关文章

  1. WPF 使用 AppBar 将窗口停靠在桌面上,让其他程序不占用此窗口的空间(附我封装的附加属性)

    原文:WPF 使用 AppBar 将窗口停靠在桌面上,让其他程序不占用此窗口的空间(附我封装的附加属性) 本文介绍如何使用 Windows 的 AppBar 相关 API 实现固定停靠在桌面上的特殊窗 ...

  2. 在linux下,查看一个运行中的程序, 占用了多少内存

    1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有 (1). ps aux: 其中  VSZ(或VSS)列 表示,程序占用了多少虚拟内存. RSS列 表示, 程序占用了多少物 ...

  3. Linux:使用rpcgen实现64位程序调用32位库函数

    摘要:本文介绍使用rpcgent实现64位程序调用32位库函数的方法,并给出样例代码. 我的问题 我的程序运行在64位Linux系统上,需要使用一个从外部获得的共享库中的函数,这个共享库是32位的,无 ...

  4. 32 bit 与 64 bit 程序(2)比较

    32 bit  与 64 bit 程序(2)区别 由于操作系统内存分配的不同,导致软件开发过程中,需要编译不同版本的软件. 几个重要概念:  (1)这里所说的的32位与64位程序,是指经过编译器编译后 ...

  5. 32 bit 与 64 bit 程序(1)如何识别?

    一, 怎样判断一个exe可执行程序是32位的还是64位的? 简单的方法: 一般来说在64位的windows7下,打开任务管理器可以知道哪些程序是32位的哪些是64位的,但是因为自己的电脑是64位的wi ...

  6. Linux:32/64位程序(应用程序、共享库、内核模块)

    摘要: Linux系统区分32/64位,相应地,应用程序.共享库和内核模块也区分32/64位. 本文以Ubuntu系统为例,介绍如何编译和使用32/64位的应用程序.共享库和内核模块. 1. 应用程序 ...

  7. 64位程序,long*转long 出错

    原因: long*在64位程序中占8个字节,long占4个字节.强转会出错. 解决方法: 把long用long long替换,long long 占8个字节

  8. C# Winform程序CPU占用高的原因和解决方法

    程序CPU占用高的可能原因: 1.存在死循环: 为什么死循环会导致CPU占用高呢?      虽然分时操作系统是采用时间片的机制对CPU的时间进行管理的,也就是说到了一定时间它会自动从一个进程切换到下 ...

  9. 64位程序调用32DLL解决方案

    最近做一个.NETCore项目,需要调用以前用VB6写的老程序,原本想重写,但由于其调用了大量32DLL,重写后还需要编译为32位才能运行,于是干脆把老代码整个封装为32DLL,然后准备在64位程序中 ...

随机推荐

  1. Java应用服务器之tomcat基础配置(二)

    前文我们聊了下tomcat的配置文件相关格式和组件简介以及webapp目录结构,manger部署和host managera部署,回顾请参考https://www.cnblogs.com/qiuhom ...

  2. 深入浅出Semaphore源码解析

    Semaphore通过permits的值来限制线程访问临界资源的总数,属于有限制次数的共享锁,不支持重入. 前提条件 在理解Semaphore时需要具备一些基本的知识: 理解AQS的实现原理 之前有写 ...

  3. var 的一个坑,以及 let

    选自 Typescript 中文教程. 快速的猜一下下面的代码会返回什么: for (var i = 0; i < 10; i++) { setTimeout(function() { cons ...

  4. 2万字长文包教包会 JVM 内存结构 保姆级学习笔记

    写这篇的主要原因呢,就是为了能在简历上写个"熟悉JVM底层结构",另一个原因就是能让读我文章的大家也写上这句话,真是个助人为乐的帅小伙....嗯,不单单只是面向面试学习哈,更重要的 ...

  5. python多线程之Threading

    什么是线程? 线程是操作系统内核调度的基本单位,一个进程中包含一个或多个线程,同一个进程内的多个线程资源共享,线程相比进程是“轻”量级的任务,内核进行调度时效率更高. 多线程有什么优势? 多线程可以实 ...

  6. Java实现简单的增删改查操作

    需求分析:通过数组 ,完成 对学生信息的 管理 (增删改查)创建1个 学生类创建1个 CRUD的类 – 学生管理类 并测试 在这个程序中我只运用了两个类进行操作 package com.hopu.de ...

  7. vue-过渡动画和 第三方动画库导入,带图

    vue路由过渡动画 //用transition将路由出口包裹起来 <transition name="fade" mode="out-in"> &l ...

  8. 【新生学习】第一周:深度学习及pytorch基础

    DEADLINE: 2020-07-25 22:00 写在最前面: 本课程的主要思路还是要求大家大量练习 pytorch 代码,在写代码的过程中掌握深度学习的各类算法,希望大家能够坚持练习,相信经度过 ...

  9. IO—》字节流&字符流

    字节流 一.字节输出流OutputStream OutputStream此抽象类,是表示输出字节流的所有类的超类.操作的数据都是字节,定义了输出字节流的基本共性功能方法. FileOutputStre ...

  10. Day10_ElasticSearch

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"乐优商城"获取视频和教程资料! b站在线视频 老师的码 ...