c++ 读取内存数据 基址_内存管理(仅学习)
理解linux内存管理首先得理解内存映射。
程序用的都是逻辑地址,以下为objdump反汇编程序的结果,左边一列都是逻辑地址:
000000000040053c
:
40053c: 55 push %rbp
40053d: 48 89 e5 mov %rsp,%rbp
400540: bf 4c 06 40 00 mov $0x40064c,%edi
400545: e8 e6 fe ff ff callq 400430
40054a: b8 00 00 00 00 mov $0x0,%eax
40054f: c9 leaveq
400550: c3 retq
在vmcore中,我们看到内存地址也是逻辑地址:
crash> bt 1300
PID: 1300 TASK: ffff81024fba1810 CPU: 0 COMMAND: "sshd"
#0 [ffff81026a2e9cd8] schedule at ffffffff802d9025
#1 [ffff81026a2e9da0] schedule_timeout at ffffffff802d9a6b
#2 [ffff81026a2e9df0] do_select at ffffffff801935f2
#3 [ffff81026a2e9ed0] sys_select at ffffffff80193880
#4 [ffff81026a2e9f80] system_call at ffffffff8010ad3e
MMU固件完成逻辑地址到物理地址的转换:
从上图看到转换分成两部分,段式内存管理将逻辑地址转换成线性地址,线性地址再经过页式内存管理单元转换成物理地址。
对于intel x86架构的cpu,段的基址为0,段式内存管理并不真正起作用,我们看到的逻辑地址可以理解为就是线性地址。
线性地址到物理地址的转换关系,由内核中的页表(page table)维护,下图说明了线性地址转换成物理地址的过程:
寄存器cr3中保存了进程的页基地址,它是物理地址,每个进程的页基地址都不相同,通过这样实现进程间物理地址空间隔离。
以上计算地址的“+”操作由cpu完成,而页表由内核维护。
进程内存布局
对于32位操作系统,进程的内存布局如下:
我们使用c库的malloc申请内存时,malloc调用brk()或mmap()实现堆(heap)或映射区域(memory mapping segment)的增长。
用malloc申请内存,其实申请到的不是真正的内存,而是虚拟内存,当程序使用这些内存的时候,将出发缺页异常,内核这时才分配物理内存页面给用户。
内核中,由do_page_fault函数处理缺页异常,do_page_fault调用handle_mm_fault,该函数中计算线性地址中的pgd、pud、pmd和pte值,然后调用handle_pte_fault,在handle_pte_fault函数中,调用do_anonymous_page等函数完成内存申请工作。
pmap命令读取/proc/PID/maps文件,使用该命令可以查看特定进程的内存映射情况,以下为当前bash进程的部分堆、栈、文件映射和匿名内存段信息:
linux # pmap $$
7561: bash
START SIZE RSS PSS DIRTY SWAP PERM MAPPING
0000000000400000 552K 480K 248K 0K 0K r-xp /bin/bash
000000000068f000 1180K 1104K 1104K 1104K 0K rw-p [heap]
00007fd7397b9000 20K 16K 16K 16K 0K rw-p [anon]
00007fd7399c0000 4K 4K 4K 4K 0K r--p /lib64/libdl-2.11.1.so
00007fff5ec37000 84K 24K 24K 24K 0K rw-p 0000000000000000 00:00 [stack]
以上pmap结果显示的每个地址段,在内核中由vm_area_struct结构表示,vm_area_struct结构在中定义,该结构包含地址段起始地址、结束地址、权限标志等信息。
vmcore中,通过以下方法,我们可以找到某个进程的vm_area_struct结构,查看其内存映射信息。
首先获取到进程task_struct结构的地址:
crash> bt
PID: 1300 TASK: ffff81024fba1810 CPU: 0 COMMAND: "sshd"
……
找到mm或active_mm字段的值:
crash> struct task_struct ffff81024fba1810
struct task_struct {……mm = 0xffff810273d6ef80,active_mm = 0xffff810273d6ef80,……
}
解析mm地址对应的mm_struct结构,第1个字段就是mmap:
crash> struct mm_struct 0xffff810273d6ef80
struct mm_struct {mmap = 0xffff810272b20870,……
}
解析mmap地址对应的vm_area_struct结构,就找到了该进程的一段内存映射,继续解析vm_next,就可以遍历该进程的所有内存映射:
crash> struct vm_area_struct 0xffff810272b20870
struct vm_area_struct {vm_mm = 0xffff810273d6ef80,vm_start = 47474870689792,vm_end = 47474870800384,vm_next = 0xffff810276839b50,……
}
伙伴算法
对内核而言,内存最小的分配单位为4k,为解决外部碎片问题,内核提供了伙伴算法(buddy algorithm),伙伴算法用于管理最小单位为4k的连续的内存块。
使用以下命令,可以将系统中内存相关的信息显示到/var/log/messages和dmesg中:
echo m > /proc/sysrq-trigger
由该命令打出的信息中,包含了伙伴算法管理的内存块信息:
Jul 20 01:38:39 linux197 kernel: Node 0 Normal: 1362*4kB 1137*8kB 491*16kB 336*32kB 192*64kB 100*128kB 69*256kB 34*512kB 14*1024kB 3*2048kB 795*4096kB = 3370112kB-
以上输出说明4kB的内存有1362块,8kB的连续内存有1137块,以此类推。
伙伴算法分配与回收内存的策略如下:
- 当所需的小块连续内存不足以分配时,将拆分较大块的连续内存块
- 当内存返回给内核时,若相邻的内存块为空闲内存,则与相邻的内存合并
slab
slab解决内部碎片问题,申请一块保存task_struct结构的内存,该块内存小于4k,而分配出去的内存若还是4k,则会造成内存浪费。
slab依据内核中各种数据结构为单位,进行内存分配。/proc/slabinfo提供了查询slab信息的接口。
对于系统内存的整体使用情况,我们可以通过/proc/meminfo接口查到:
cat /proc/meminfo
MemTotal: 8110624 kB
MemFree: 6336284 kB
Buffers: 78020 kB
Cached: 1514352 kB
……
free命令就是读取/proc/meminfo,进行内存信息显示的。
buffers用于块设备缓存,cached用于文件缓存。查看内核中的meminfo_proc_show函数,我们就能发现buffers与cached的具体计算方法。
执行以下dd命令,我们可以看到free命令中buffers值的增长:
dd if=/dev/sda2 of=/dev/null bs=1000 count=10000000
内存回收
对于linux server,以下两种情况会触发内核通过页帧回收算法(page frame reclaiming algorithm, PFRA)进行内存回收:
- 内存使用紧张
- 内核线程kswapd周期性回收
回收内存的方式大体有两种:
- 丢弃数据
- 将数据交换出去
下图说明了内核中回收内存相关的函数调用:
Reference: Chapter 12 - Memory Management, Linux kernel development.3rd.Edition
c++ 读取内存数据 基址_内存管理(仅学习)相关推荐
- c++ 读取内存数据 基址_手机相册里面照片多太占内存,但又不想删掉,该怎么办?...
手机相册里面照片多太占内存,但又不想删掉,该怎么办? 和我一样,我也是特别喜欢拍照的人,所以手机相册里的照片有上万张-- 你说要删掉?那不可能!经过千挑万选留下的照片怎么可能舍得删! 我的手机虽然是支 ...
- 19.jvm内存结构部分——堆_内存诊断_jmap
接下来我们给大家介绍一下堆内存的一个诊断. 这里主要先介绍一些堆内存诊断相关的一些工具. 我们接下来会掌握这样几个工具啊, 第一个叫 jps 的工具,它是查看当前系统中有哪些java 进程,并且把它们 ...
- 问答|数据中心运维管理VIP学习群
今天在数据中心运维管理VIP学习群里有群友提问现在北京的数据中心是否可以申请降低基础电费?群里的张总已经回答:三个月可以申请一次调整基础容量. 数据中心一旦运行,永不停歇,所以数据中心是用电大户也被称 ...
- rdd数据存内存 数据量_大数据开发-Spark调优常用手段
Spark调优 spark调优常见手段,在生产中常常会遇到各种各样的问题,有事前原因,有事中原因,也有不规范原因,spark调优总结下来可以从下面几个点来调优. 1. 分配更多的资源 分配更多的资源: ...
- rdd数据存内存 数据量_「大数据」(七十七) Spark之IO机制
[导读:数据是二十一世纪的石油,蕴含巨大价值,这是·情报通·大数据技术系列第[77]篇文章,欢迎阅读和收藏] 1 基本概念 与传统的 IO 相比, Spark IO 有很大区别.传统的数据存在单个计算 ...
- 使用qsort对不连续的内存数据排序_常见的内排序和外排序算法
常见的内排序算法 所谓的内排序是指所有的数据已经读入内存,在内存中进行排序的算法.排序过程中不需要对磁盘进行读写.同时,内排序也一般假定所有用到的辅助空间也可以直接存在于内存中.与之对应地,另一类排序 ...
- rdd数据存内存 数据量_超全spark性能优化总结
Spark是大数据分析的利器,在工作中用到spark的地方也比较多,这篇总结是希望能将自己使用spark的一些调优经验分享出来. 一.常用参数说明 --driver-memory 4g : drive ...
- java构建内存池队列_内存池完整实现代码及一些思考
为了提高效率和有效的监控内存的实时状态,我们采取了内存池的思想来解决效率与对内存实现监控的问题. 网上查找到了一些方案,根据自己的理解实现了应用. 我们什么时候要调用到内存池, 1,当我们频繁的申请释 ...
- phpfpm内存越来越高_内存时序越小越好,为什么DDR1到DDR4 时序值越来越高了?
内存参数中除了容量.频率外,一般还有一组由四个用破折号分割的数字串,这就是内存的时序. 1.如何查看内存时序 购买内存时,一般参数中都会标注内存的时序信息. 使用中的内存可以用 CPUZ 进行查看. ...
最新文章
- 怎样增加混凝土粘聚性_改善中低强度等级混凝土粘聚性的方法
- 初学者学python好还是c-C 和 Python语言先学哪个好?
- Django多进程中的查询错乱问题以及mysql gone away问题
- 数学建模——智能优化之遗传算法详解Python代码
- 实现查询菜品信息考试题
- P4145-上帝造题的七分钟2/花神游历各国【并查集,树状数组】
- virtualbox 使用
- 不是bug!百度集好运卡奖品追加8000个金猪
- pytroch中的Variable()介绍
- V4L2视频采集与H264编码4—X264编码H264视频
- Qt+opencv二值化
- c语言图像对比度增强,图像对比度增强实验分析报告.doc
- Nessus下载及安装
- 2022年6月 青少年软件编程(Python) 等级考试试卷(二级)
- vue 组件通信合集
- 【转】.NET引用Excel操作时无法关闭Excel.exe进程的解决方法
- c语言代码查错软件,Ubuntu下面的C语言代码检查工具 Splint
- 安卓开发为什么选择用Java语言
- iOS开发-常用的数学方法
- 动漫人物的躯干如何画