Linux 内存管理概述(偏实战,略理论,附链接)

基础理论

1. 内存映射

可以参考: Linux内存映射 - 知乎 写的很详细,而且也有代码分析

2. 虚拟内存的空间分布

通过这张图你可以看到,用户空间内存,从低到高分别是五种不同的内存段。只读段,包括代码和常量等。数据段,包括全局变量等。堆,包括动态分配的内存,从低地址开始向上增长。文件映射段,包括动态库、共享内存等,从高地址开始向下增长。栈,包括局部变量和函数调用的上下文等。栈的大小是固定的,一般是 8 MB。

内存分配

malloc() 是 C 标准库提供的内存分配函数,对应到系统调用上,有两种实现方式,即 brk() 和 mmap()。

对小块内存(小于 128K),C 标准库使用 brk() 来分配,也就是通过移动堆顶的位置来分配内存。这些内存释放后并不会立刻归还系统,而是被缓存起来,这样就可以重复使用。

brk() 方式的缓存,可以减少缺页异常的发生,提高内存访问效率。不过,由于这些内存没有归还系统,在内存工作繁忙时,频繁的内存分配和释放会造成内存碎片。

而大块内存(大于 128K),则直接使用内存映射 mmap() 来分配,也就是在文件映射段找一块空闲内存分配出去。

mmap() 方式分配的内存,会在释放时直接归还系统,所以每次 mmap 都会发生缺页异常。在内存工作繁忙时,频繁的内存分配会导致大量的缺页异常,使内核的管理负担增大。这也是 malloc 只对大块内存使用 mmap 的原因。

如果遇到比页(4k)更小的对象,比如不到 1K 的时候,该怎么分配内存呢?

实际系统运行中,确实有大量比页还小的对象,如果为它们也分配单独的页,那就太浪费内存了。所以,在用户空间,malloc 通过 brk() 分配的内存,在释放时并不立即归还系统,而是缓存起来重复利用。在内核空间,Linux 则通过 slab 分配器来管理小内存。你可以把 slab 看成构建在伙伴系统上的一个缓存,主要作用就是分配并释放内核中的小对象。对内存来说,如果只分配而不释放,就会造成内存泄漏,甚至会耗尽系统内存。所以,在应用程序用完内存后,还需要调用 free() 或 unmap() ,来释放这些不用的内存。

内存回收以及相关命令

- 回收缓存,比如使用 LRU(Least Recently Used)算法,回收最近使用最少的内存页面;

- 回收不常访问的内存,把不常用的内存通过交换分区直接写到磁盘中;(swap)

- 杀死进程,内存紧张时系统还会通过 OOM(Out of Memory),直接杀掉占用大量内存的进程。(通过打分oom_score: 进程的 oom_score 越大,代表消耗的内存越多,也就越容易被 OOM 杀死,从而可以更好保护系统.)

如何查看内存使用情况

  1. free: 显示总共内存使用情况以及swap

available 不仅包含未使用内存,还包括了可回收的缓存,所以一般会比未使用内存更大。不过,并不是所有缓存都可以回收,因为有些缓存可能正在使用中。

# 注意不同版本的free输出可能会有所不同 $ free total used free shared buff/cache available Mem: 8169348 263524 6875352 668 1030472 7611064 Swap: 0 0 0 第一列,total 是总内存大小; 第二列,used 是已使用内存的大小,包含了共享内存; 第三列,free 是未使用内存的大小; 第四列,shared 是共享内存的大小; 第五列,buff/cache 是缓存和缓冲区的大小; 最后一列,available 是新进程可用内存的大小。

2. top

VIRT 是进程虚拟内存的大小,只要是进程申请过的内存,即便还没有真正分配物理内存,也会计算在内。

RES 是常驻内存的大小,也就是进程实际使用的物理内存大小,但不包括 Swap 和共享内存。

SHR 是共享内存的大小,比如与其他进程共同使用的共享内存、加载的动态链接库以及程序的代码段等。

%MEM 是进程使用物理内存占系统总内存的百分比。

注意:第一,虚拟内存通常并不会全部分配物理内存。从上面的输出,你可以发现每个进程的虚拟内存都比常驻内存大得多。

第二,共享内存 SHR 并不一定是共享的,比方说,程序的代码段、非共享的动态链接库,也都算在 SHR 里。当然,SHR 也包括了进程间真正共享的内存。所以在计算多个进程的内存使用时,不要把所有进程的 SHR 直接相加得出结果。

内存泄漏的排除有效方法

memleak(bcc包中GitHub - iovisor/bcc: BCC - Tools for BPF-based Linux IO analysis, networking, monitoring, and more)跟踪系统、指定进程的内存分配,释放请求,然后定期输出一个未释放内存和相应调用栈的汇总情况(5s)

/usr/share/bcc/tools/memleak -p $(pidof app) -a
Attaching to pid 12512, Ctrl+C to quit.
[03:00:41] Top 10 stacks with outstanding allocations:addr = 7f8f70863220 size = 8192addr = 7f8f70861210 size = 8192addr = 7f8f7085b1e0 size = 8192addr = 7f8f7085f200 size = 8192addr = 7f8f7085d1f0 size = 819240960 bytes in 5 allocations from stackfibo+0x1f [app]child+0x4f [app]start_thread+0xdb [libpthread-2.27.so] 

可以看出fibo() 这function在分配stack栈空间。

然后通过各种搜索工具找到fibo这个 function,逐行代码分析。


long long *fibo(long long *n0, long long *n1)
{//分配1024个长整数空间方便观测内存的变化情况long long *v = (long long *) calloc(1024, sizeof(long long));*v = *n0 + *n1;return v;
}void *child(void *arg)
{long long n0 = 0;long long n1 = 1;long long *v = NULL;for (int n = 2; n > 0; n++) {v = fibo(&n0, &n1);n0 = n1;n1 = *v;printf("%dth => %lld\n", n, *v);sleep(1);}
}

可以知道调用一次fibo,就会用 calloc()分配一次内存,但是从没发现哪里free这个空间。

所以我们需要修复它:

void *child(void *arg)
{...for (int n = 2; n > 0; n++) {v = fibonacci(&n0, &n1);n0 = n1;n1 = *v;printf("%dth => %lld\n", n, *v);free(v);    // 释放内存sleep(1);}
} 

大功告成!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2813291.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

试用北大库博Cobot-SCA工具

最近试用北大软件工具的库博-SCA工具,其产品全称是库博软件成分分析与同源漏洞检测工具软件。这个产品名称有点长,至于原因,可能是为了与市场上其它SCA工具进行区分吧。北大库博SCA不是像大多数SCA工具,解析构建文件中的依赖组件进…

亿道丨三防平板丨手持平板丨加固平板丨助力地震救援

自土耳其发生7.8级大地震以来,一直都牵动着世人的心。2023年2月10日,据法新社最新消息,强震已造成土耳其和叙利亚两国超2万人遇难。报道称,相关官员和医护人员表示,地震造成土耳其17674人死亡,叙利亚则有33…

Linux--查看网络性能指标

一、性能指标有哪些? 带宽,表示链路的最大传输速率,单位是 b/s (比特 / 秒),带宽越大,其传输能力就越强。延时,表示请求数据包发送后,收到对端响应,所需要的…

跟着cherno手搓游戏引擎【25】封装2DRenderer,封装shader传参,自定义Texture

封装2DRenderer&#xff1a; Renderer.h: #include"ytpch.h" #include"Renderer.h" #include <Platform/OpenGL/OpenGLShader.h> #include"Renderer2D.h" namespace YOTO {Renderer::SceneData* Renderer::m_SceneData new Renderer::S…

在IDEA中创建vue hello-world项目

工作中最近在接触vue前端项目&#xff0c;记录一下从0搭建一个vue hello world项目的步骤 1、本地电脑安装配置node、npm D:\Project\vue\hello-world>node -v v14.21.3 D:\Project\vue\hello-world>npm -v 6.14.18 D:\Project\vue\hello-world> 2、设置npm国内淘…

C语言指针总结2

前言 本篇博客紧接着指针总结1来总结下数组和指针的关系&#xff0c;让我们一起来看一下数组与指针的“爱恨情仇”。 欢迎关注个人主页&#xff1a;小张同学zkf 若有问题&#xff0c;评论区见 文章目录 1. 数组名的理解2. 使用指针访问数组3. 一维数组传参的本质4. 冒泡排序5.…

Layer1 明星项目 Partisia Blockchain 何以打造互操作、可创新的数字经济网络

我们的目标是创建一个以用户为中心的全新数字经济网络&#xff1a;在去信任化和公平透明的环境下&#xff0c;所有的隐私数据都能够得到天然保障&#xff0c;企业、用户等各角色的协作与共享将会更顺利地进行。 —— Partisia Blockchain 团队 作为一个以 Web3 安全为技术方向的…

数字化转型与制造企业绿色创新质量——基于供需双侧机制的再检验(2011-2022年)

参照马红&#xff08;2023&#xff09;的做法&#xff0c;本团队对来自软科学《数字化转型与制造企业绿色创新质量—基于供需双侧机制的再检验》一文中的基准回归部分进行复刻 一、数据介绍 数据名称&#xff1a;数字化转型与制造企业绿色创新质量 参考期刊&#xff1a;《软…

ClickHouse 指南(三)最佳实践 -- 跳数索引

Data Skipping Indexes Data Skipping Indexes 2 1、简介 影响ClickHouse查询性能的因素很多。在大多数情况下&#xff0c;关键因素是ClickHouse在计算查询WHERE子句条件时是否可以使用主键。因此&#xff0c;选择适用于最常见查询模式的主键对于有效的表设计至关重要。 然…

光学3D表面轮廓仪微纳米三维形貌一键测量

光学3D表面轮廓仪(白光干涉仪)利用白光干涉原理&#xff0c;以0.1nm分辨率精准捕捉物体的表面细节&#xff0c;实现三维显微成像测量&#xff0c;被广泛应用于材料学领域的研究和应用。 了解工作原理与技术 材料学领域中的光学3D表面轮廓仪&#xff0c;也被称为白光干涉仪&am…

05 动力云客之分页查询用户 + 查询用户详情 + 新增用户

1. 用户列表分页查询实现 核心 使用pageHelper实现分页 GetMapping(value "api/users")//分页的参数可以不传, 不传就默认设置为1public R userPage(RequestParam(value "current", required false) Integer current) {if (current null) {current …

STM32—PWM输出

目录 1 、 电路构成及原理图 2 、编写实现代码 main.c pwm.c 3、代码讲解 4、烧录到开发板调试、验证代码 5、检验效果 此笔记基于朗峰 STM32F103 系列全集成开发板的记录。 1 、 电路构成及原理图 PWM---Pulse Width Modulation&#xff0c;脉冲宽度调制&#xff0c;是…

通过跳板机拷贝远程服务器文件

## 背景 在日常开发或者运维中&#xff0c;经常会遇到开发环境与线上环境网络隔离&#xff0c;需要通过跳板机连接的场景&#xff0c;如果需要将目标机器上的定位信息搬迁到开发机做进一步排查时&#xff0c;经常取文件比较费劲&#xff0c;一般操作是将目标文件拷贝到跳板机&…

Bert-as-service 学习

pip3 install --user --upgrade tensorflow 安装遇到的问题如下&#xff1a; pip3 install --user --upgrade tensorflow 1052 pip uninstall protobuf 1053 pip3 uninstall protobuf 1054 pip3 install protobuf3.20.* 1055 pip3 install open-clip-torch2.8.2 1…

单片机精进之路-5矩阵键盘扫描

如下图&#xff0c;先在p3口输出0xfe&#xff0c;再读取p3口的电平&#xff0c;如果没有按键按下&#xff0c;temp & 0xf0还是0xf0&#xff0c;如果又第一个键按下&#xff0c;temp & 0xf0还是0xee&#xff0c;其他按键由此类推可得。 //4*4键盘检测程序,按下键后相应…

[C++核心编程](二):引用

目录 基本语法 引用做函数参数 引用做函数返回值 常量引用 基本语法 给变量取别名&#xff1a;数据类型 &别名 原名&#xff1b; 本质&#xff1a;指针常量&#xff08;指针的指向不可改&#xff0c;指向的值可改&#xff09; int value 10;int &index value; …

贪心算法(算法竞赛、蓝桥杯)--修理牛棚

1、B站视频链接&#xff1a;A27 贪心算法 P1209 [USACO1.3] 修理牛棚_哔哩哔哩_bilibili 题目链接&#xff1a;[USACO1.3] 修理牛棚 Barn Repair - 洛谷 #include <bits/stdc.h> using namespace std; const int N205; int m,s,c,ans; int a[N];//牛的位置标号 int d[N…

将仓库A中的部分提交迁移到仓库B中

结论&#xff1a; 使用git format-patchgit am即可实现 使用场景&#xff1a; 例如仓库A这里有5个提交记录&#xff0c;commitid1, commitid2, commitid3, commitid4&#xff0c;commitid5 仓库B想用仓库A中提交的代码&#xff0c;手动改比较慢&#xff0c;当改动较多的时候…

【kubernetes】二进制部署k8s集群之cni网络插件flannel和calico工作原理

k8s集群的三种接口 k8s集群有三大接口&#xff1a; CRI&#xff1a;容器进行时接口&#xff0c;连接容器引擎--docker、containerd、cri-o、podman CNI&#xff1a;容器网络接口&#xff0c;用于连接网络插件如&#xff1a;flannel、calico、cilium CSI&#xff1a;容器存储…

人大金仓与mysql的差异与替换

人大金仓中不能使用~下面的符号&#xff0c;字段中使用”&#xff0c;无法识别建表语句 创建表时语句中只定义字段名.字段类型.是否是否为空 Varchar类型改为varchar&#xff08;长度 char&#xff09; Int(0) 类型为int4 定义主键&#xff1a;CONSTRAINT 键名 主键类型&#x…