读取当前linux进程内存_(笔记)Linux上的内存分配

作者: LemonNan

原文: https://juejin.im/post/5ee3c34a518825430c3ad31d

前言

本篇是对Linux内存分配的一个学习笔记.

程序内存结构

下面是在 Linux/x86-32 中典型的一个进程内存结构

c20e9374e3f9956b4ad67b645d4b6c8e.png

  • 文本段包含了进程运行的程序机器语言指令. 文本段具有只读属性, 以防止进程通过勘误指针意外修改自身指令. 因为多个进程可以同时运行同一程序, 所以又将 文本段设为可共享 , 这样一份程序代码的拷贝可以映射到所有这些进程到虚拟地址空间中.

  • 初始化数据段包含显示初始化的全局变量和静态变量. 程序加载到内存时, 从可执行文件中读取这些变量的值.

  • 未初始化数据段包含了未进行显示初始化的全局变量和静态变量 . (书上写了一堆, 实际上就是懒加载)

  • 栈(stack)是一个动态增长和收缩的段, 由栈帧(stack frames)组成 . 系统会为每个当前调用的函数分配一个栈帧.栈帧中存储局部变量(所谓自动变量), 实参和返回值.

  • 堆(heap)时刻在运行时(为变量)动态进行内存分配的一块区域, 堆顶端称做 program break .

3g(32位)以上的虚拟内存地址, 程序无法访问.

程序的起始地址为 0x08048000 (32位)、0x00400000 (64位)

malloc 和 free

malloc

void *malloc(size_t size);
  • 栈向下增长超出之前曾达到的位置

  • 挡在堆中分配或者释放内存时, 通过调用 brk()、sbrk() 或 malloc 函数族来提升 program break 的位置.

  • 调用 shmat() 连接 System V 共享内存区或者当调用 shmdt() 脱离共享内存区时.

  • 调用 mmap() 创建内存映射或者 munmap() 解除内存映射

特点

  • malloc() 返回的内存快所采用的字节对齐的方式, 在大多数的硬件架构上, 意味着 malloc 是基于 8字节 或者 16字节 边界来分配内存的.

  • malloc 之后的内存, 在不使用的需要需要手动 free, malloc 和 free 一一对应, 否则可能会导致 未知错误(多次free) 或者 内存泄漏(没有调用free).

  • 允许分配小块内存

  • 允许随意释放内存快, 它们被维护于一张空闲内存列表中, 在后续内存分配调用时循环使用

free

free() 函数释放 ptr 参数所指向的内存快

void free(void *ptr);

特点

  • free 并不降低 program break 的位置, 而是将这块内存添加到空闲内存列表, 供后续的 malloc() 函数循环使用.这么做有几个原因:

    • 被释放的内存快通常位于堆的中间, 而非堆堆顶部, 因而降低 program break 不能达到效果

    • 最大限度减少程序必须执行 sbrk() 调用次数(减少系统调用的开销)

  • free 传入空指针不会做任何处理(从设计上来说这不是错误代码)

  • 调用 free 后堆参数 ptr 的使用, 比如再次调用 free, 会产生错误并且可能导致不可预知的结果.

为什么是8/16字节对齐

  • CPU 读取8字节对齐, 比如 double/long, 不对齐的话需要读写2次

  • CPU高速缓存行大小通常是 32 或者 64 字节. 如果对象是8字节对齐的数据, 则只需要占用一个缓存行, 如果不是8字节对齐的话, 则可能一部分数据在一个缓存行, 另一部分数据在其它的缓存行, 所以读写这个数据需要用到2个缓存行的数据而不是一个, 所有(目前1、2、3)级别的缓存都会受到此影响.

  • 对于在磁盘中的数据, 都是以512字节为最低的单位(一个扇区的数据大小), 如果是8字节对齐的话, 则数据会被存放在一个扇区里, 可以只通过一次读取将数据都读取出来, 如果数据不是8字节对齐, 则 数据可能会被存放到不同的扇区中, 并且还有可能不是相邻的扇区, 这就会 导致随机I/O , 降低数据处理的效率, 消耗更多的硬件资源. 对于上层来说, 数据是相连的(逻辑), 但是对于底层的物理硬件来说, 数据很有可能位于不相邻的扇区(数据处理最小单元).

so, 总结下来就是, 非对齐的数据访问 会因为增加硬件访问次数 比对齐的数据访问效率低.

说起缓存行, Java中有一些框架(比如Disruptor)考虑到了不同的CPU架构, 使用了CPU支持的缓存行填充, 以防止 伪共享(这里暂不做过多描述) 的发生从而降低效率.

通过 sysctl -a 查看

# 我的电脑中的数据hw.cachelinesize: 64hw.l1icachesize: 32768hw.l1dcachesize: 32768hw.l2cachesize: 262144hw.l3cachesize: 3145728

虚拟内存管理

内核为每一个进程都维护一张页表(page table) , 页表中的每个条目要么指出一个虚拟页面在 RAM 中的所在位置, 要么表明其当前驻留在磁盘上, 若进程访问的地址并无页表条目与之对应, 进程将会收到一个 SIGSEGV 信号.

Q: 虚拟页面的数据为什么会在磁盘上?

A: 每个程序中只有一部分 page 会驻留在 物理内存(RAM) 中, 未使用的 page 会被拷贝保存到交换区(swap area)内, 这是磁盘空间中的保留区域, 作为 RAM 的补充, 只有在需要的时候才会载入 物理内存.

进程在读取的时候, 如果访问的页面没有驻留在物理内存中, 将会发生页面错误(page fault), 内核即刻挂起的执行, 同时从磁盘中将该页面载入内存.

在 x86-32 中, page size 为 4096 字节(4KB), 一些其它的Linux使用的页面比 4096 字节更大.

Alpha 使用的 page size = 8192 字节(8KB), IA-64 的page size是可以改变的, 默认为 16384 字节.程序通过调用 sysconf(_SC_PAGESIZE) 获取系统虚拟内存的 page size.


虚拟内存的实现需要硬件中分页内存管理单元(PMMU)的支持, PMMU 把要访问的每个虚拟内存地址转换成相应的物理内存地址, 当特定虚拟内存地址所对应的页没有驻留于 RAM 中时, 将以页面错误(page fault)通知内核.

有效虚拟内存范围

由于 内核能为进程分配和释放页(和页表条目) , 所以进程的有效虚拟地址范围在其生命周期中可以发生变化. 如下场景会导致范围变化:

  • 栈向下增长超出之前曾达到的位置

  • 挡在堆中分配或者释放内存时, 通过调用 brk()、sbrk() 或 malloc 函数族来提升 program break 的位置.

  • 调用 shmat() 连接 System V 共享内存区或者当调用 shmdt() 脱离共享内存区时.

  • 调用 mmap() 创建内存映射或者 munmap() 解除内存映射

局部性原理

在计算机中大多数程序都有一个共同特点, 访问局部性 .

访问局部性包含两方面:

  • 空间局部性: 程序倾向于访问在最近访问过的内存地址附近的内存(由于指令是顺序执行的, 并且有时会按顺序处理数据结构)

  • 时间局部性: 这意味着数据被访问到, 在之后较短的时间内会被再次访问到(可能是由于循环)

优点

虚拟内存使得进程的虚拟地址空间和RAM的物理地址空间隔离开, 有以下一些好处

  • 进程与进程、进程与内核相互隔离, 所以一个进程不能读取其它进程或内核的内存, 因为每个进程的页表条目指向截然不同的物理内存地址.

  • 适当情况下, 多个进程鞥狗共享内存. 因为不同的进程页表条目可以指向相同的物理内存(RAM)地址.通常发生在如下的场景:

    • 执行同一程序的多个进程, 共享一份程序代码副本. 当多个进程执行相同的程序文件(或加载相同的共享库), 会隐式实现这一类型的共享.

    • 进程通过 shmget() 和 mmap() 系统调用显示请求与其它进程共享内存, 这样的目的是为了进程间的通信.

  • 实现保护机制: 相同的内存, 不同的进程可以设置不同的访问权限, 某些进程只读、某些拥有所有权限等.

  • 因为需要驻留在内存中的仅是程序的一部分, 所以程序的加载和运行都变快了, 而且一个程序所占用的大小(虚拟内存) 能够超出 RAM 容量.(因为有的事通过虚拟内存管理存放到了磁盘上)

一个进程所使用的RAM减少了, RAM中同时可容纳的进程数量增多. 这样的话加大了在任一时刻CPU可执行至少一个进程的概率, 这样往往也会提高CPU的利用率.

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php改成IP连接数据库,thinkphp,pdo连接数据库,host自动被替换成了本机ip

class DBAccess extends PDO{ private $charset; // 数据库字符集public $cacheDir_cache_$98sdf29fw!d#s4fef/; public $prename; public $time; function __construct($dsn, $user, $password){ try{ parent::__construct($dsn, $user, $pa…

django开源电子文档管理系统_「开源推荐」BookStack v2.8 发布,简洁美观的在线文档管理系统

程序介绍BookStack,基于 Mindoc、使用Go语言的Beego框架开发的功能类似GitBook和看云的在线文档管理系统,拥有简洁美观的页面布局,实现了文档采集、导入、电子书生成以及版本控制等强大的文档功能,并推出了配套的开源微信小程序 B…

matlab 随机森林算法_随机森林算法

随机森林是一种灵活,易于使用的机器学习算法,即使没有超参数调整,也能在大多数情况下产生出色的结果。它也是最常用的算法之一,因为它简单,并且可以用于分类和回归任务。在这篇文章中,您将学习随机森林算法…

opengl 纹理贴到对应的位置_一步步学OpenGL(27) -《公告牌技术与几何着色器》

教程 27公告牌技术与几何着色器原文: http://ogldev.atspace.co.uk/www/tutorial27/tutorial27.htmlCSDN完整版专栏: https://blog.csdn.net/cordova/article/category/9266966背景从最初的一系列教程我们已经应用过了顶点着色器和片段着色器&#xff0c…

python 当前目录_virtualenvwrapper打造多版本Python环境

前言面对多个 Python 开发项目时,需要针对不同的项目创建相应的开发环境。通常情况下,使用 virtualenv 创建一个虚拟的独立 Python 环境,但是 virtualenv 创建的环境相对分散不便于管理。这里推荐使用 virtualenvwrapper 来创建集中的便于管理…

oracle装了客户端怎么登陆账号,分享Oracle 11G Client 客户端安装步骤(图文详解)...

Oracle 11G Client 客户端安装步骤,具体如下:下载地址:http://www.gimoo.net/database/167737.html先将下载下来的ZIP文件解压,并运行setup.exe文件。执行到第四步之后,出现错误,直接点全部忽略就可以了。把…

python与excel互通_【python】python vs Excel ( 与mysql数据库之间的交互)

【python】python vs Excel ( 与mysql数据库之间的交互) 通过python与mysql数据库做交互 到目前为止大部分案例的演示数据都是基于文件进行读取的。那么python如何跟数据库之间做交互才是未来我们真正需要关心的。因为我们的数据最终还是要存储到数据库中去的。 python与数据库…

基于matlab的车牌识别系统程序,基于matlab的车牌识别系统的设计(附程序).doc

基于matlab的车牌识别系统的设计(附程序).doc 1车牌识别系统的设计1.摘要:汽车牌照自动识别系统是制约道路交通智能化的重要因素,包括车牌定位、字符分割和字符识别三个主要部分。本文首先确定车辆牌照在原始图像中的水平位置和垂直位置,从而定位车辆牌照…

python英文词云代码_使用python实现个性化词云的方法

先上图片词云图 需要模板 pip install jieba pip install wordcloud 还需要安装另外两个东西这两个我也不太懂借鉴百度写上去的 pip install scipy pip install matplotlib 因为用ubuntu系统所有没有windows那么麻烦,也没有那么多报错 看到好多人制作自己的词云有没…

linux监测node进程,通过node_exporter监控linux服务器一

前言:node_exporter用于监控*nux系统,使用go编写的收集器prometheus服务器:192.168.199.222监控服务器 192.168.199.221在192.168.199.221下载node_exporterwget https://github.com/prometheus/node_exporter/releases/download/v*/node_exp…

k8s 离线安装_阿里开源 k8s 事件通知服务

背景在 Kubernetes 开源生态中,资源监控有 metrics-server、Prometheus等,但这些监控并不能实时推送 Kubernetes 事件,监控准确性也不足。当 kubernetes 集群中发生 Pod因为 OOM 、拉取不到镜像、健康检查不通过等错误导致重启,集…

kali linux解密栅栏密码,最详细bugku加密小白解法---持续更新!

bugku加密!安排本文持续更新1 摩斯密码2 栅栏密码3 Ook密码4 brain密码5 easycrypto密码6 base647 散乱的密文8 凯撒密码9 一段base6410 !?11 []-12 奇怪的密码--凯撒变式13 托马斯杰斐逊--转轮加密14 伪加密15 告诉你个秘密16 这不是MD517 贝…

linux命令 重定向%3e,linux输出信息调试信息重定向

在运行linux的时候有所有的调试信息可以分为三个部分1、bootloader输出信息U-Boot 1.3.2(Nov 19 2016 - 22:02:08)DRAM: 64 MBFlash: 512 kBNAND: 64 MiBIn: serialOut: serialErr: serialHit any key to stop autoboot: 0[yqliu2410 #] tftpFound DM9000 ID:90000a46 at addre…

360加固一键脱壳工具2020_如何脱壳加固过的Apk并利用其API“走近数据库”

0x00 寻找突破口打开首页,emm就一个登录页面,没了随便写点东西提交看看天生手欠的我一不小心就多输了一个单引号WDNMD,除了数字和字母其他都不行?这叫我怎么测?刚刚要放弃,就在这时,首页的一个二维码吸引了我正是安卓端的软件,眼前一亮,仿佛找到了打开新世界的大门开开心心地…

python 函数递归_Python零基础之三元表达式、函数递归、匿名函数教程!超级详细!...

目录一、三元表达式二、函数递归 递归调用的定义递归分为两个阶段:递归,回溯三、匿名函数 什么是匿名函数?有名字的函数与匿名函数的对比lambda匿名函数的应用四、内置函数 #注意:内置函数id()可以返回一个对象的身份,…

linux 内核空间占用cpu百分比过高,linux下分析java程序占用CPU、内存过高

一、CPU过高分析1)使用TOP命令查看CPU、内存使用状态可以发现CPU占用主要分为两部分,一部分为系统内核空间占用CPU百分比,一部分为用户空间占用CPU百分比。其中CPU状态中标示id的为空闲CPU百分比。当空闲CPU百分比越低,说明CPU占用率越高。2)…

springboot 获取application参数_LOOK ! SpringBoot的外部化配置最全解析

本篇要点介绍各种配置方式的优先级。介绍各种外部化配置方式。介绍yaml的格式及原理。介绍如何绑定并测试类型安全的属性配置。介绍ConfigurationProperties与Value的区别。一、SpringBoot官方文档对于外部化配置的介绍及作用顺序SpringBoot支持多种外部化配置,以便…

spark入门_入门必读 | Spark 论文导读

Resilient Distributed Datasets: A fault-tolerant abstraction for in-Memory cluster computing, 是讲述 Spark RDD 的基础论文,通读论文能给我们带来全景的 Spark 知识面摘要:RDD,全称Resilient Distributed Dataset,可伸缩性数据集。使用…

Qt在linux下无法输入中文,Ubuntu使用集成开发环境QT无法输入中文的解决方法

QT Creator是轻量级集成开发环境,在Ubuntu系统操作中,使用QT时无法输入中文,遇到这种情况要如何处理呢?下面小编就给大家介绍下Ubuntu如何解决QT无法输入中文问题。1 安装搜狗输入法,(如果你想用ubuntu自带的输入法也没…

altium pcb 信号高亮_在PCB设计中高效的放置元件技巧

在印刷电路板设计中,设置电路板轮廓后,将零件(占地面积)调用到工作区。然后将零件重新放置到正确的位置,并在完成后进行接线。组件放置是这项工作的第一步,对于之后的平滑布线工作是非常重要的工作。如果在接线工作期间模块不足&a…