内存原理 | 内存分配 | 内存对齐

简介: 内存原理 | 内存分配 | 内存对齐

虚拟地址空间

  • 内核空间:进程管理、设备管理、虚拟文件管理
  • 用户空间
  • 栈空间 stack:存储局部变量,函数参数
  • 内存映射段 mmap:静态库与动态库,文件映射,匿名映射
  • 堆空间 heap:malloc / calloc / new
  • 读写段:全局变量、静态变量
  • 只读段:文字常量区(字符串常量)和程序代码区(二进制代码)


* 堆和栈的区别


管理方式 程序员手动控制,memory leak 编译器管理
空间大小 内存区域不连续(空闲链表),受限于虚拟地址空间,例如:32 位系统 4 G 内存区域连续,空间大小固定。操作系统预设,一般是 2 M。
内存管理 系统遍历内存空闲链表,寻找第一个大于所需空间的空闲结点,将其分配给程序。 栈的剩余空间大于申请空间,系统为程序提供内存,否则异常栈溢出。
碎片问题 频繁的内存申请释放,造成内存空间不连续,产生大量的碎片 栈后进先出,没有内存碎片
生长方向 堆向上生长,向高地址方向增长 栈向下生长,向低地址空间增长
分配方式 动态分配 系统提供静态和动态的方式
分配效率 效率低,间接寻址,第一次访问指针,第二次访问指针指向的内存 效率高,计算机底层提供支持(寄存器、指令等)


内存分配

动态内存分配系统调用

int brk(void *addr);            // 返回对的顶部地址
 void *sbrk(intptr_t increment);  // 扩展堆,increment 指定要增加的大小

先通过 sbrk 扩展堆,将这部分空闲内存空间作为缓冲池,然后通过 malloc/ free 管理缓冲池中的内存。

* malloc 原理

malloc 使用空闲链表组织堆中的空闲区块,每个内存区块由内存控制块 mem_control_block + 可用内存空间组成。malloc 返回的是内存控制块后的地址,即可用内存空间的起始地址。

struct mem_control_block {
   int is_available; // 是否可用(如果还没被分配出去,就是 1)
   int size;         // 实际空间的大小
 };

malloc 分配时遍历空闲链表,以首次适应算法为例,寻找第一个大于所需空间的空闲区块,然后将其分配给程序,返回这可用空间的指针。如果没有这样的内存块,则向操作系统申请扩展堆内存。若空闲区块空间有剩余,系统自动将多余的部分重新放入空闲链表。

常见的内存匹配算法有

  • 首次适应法
  • 最佳适应法
  • 最差适应法
  • 下一个适应法

* free 原理

free 将内存区块重新插入到空闲链表,free 只接受一个指针,却可以释放恰当大小的内存,这是因为在内存控制块保存了该区域的大小。

被 free 回收的内存首先被 ptmalloc 使用双向链表保存起来,当用户下一次申请内存时,会尝试从这些内存中寻找合适的返回,避免了频繁的系统调用,占用过多的系统资源。同时 ptmalloc 也会尝试对小块内存进行合并,避免产生过多的内存碎片。

内存对齐

内存的自然对齐:按照结构体中最大数据成员对齐。

  • 结构体内成员按照声明顺序存储,第一个成员地址和整个结构体地址相同。
  • 结构体的首地址必须是最大数据成员大小的整数倍
  • 每个成员相对于结构体首地址的偏移量必须是该成员大小的整数倍,否则填充字节。
  • 整个结构体的大小必须是最大数据成员大小的整数倍,否则填充字节。

对齐系数:#pragma pack(n)

#pragma pack(n) // 按照 n (2 的 n 次幂)个字节对齐
 #pragma pack()  // 取消自定义字节对齐方式

* 内存对齐的规则

  • 数据成员对齐规则:第一个数据成员放在偏移 0 的地方,每个数据成员的对齐按照#pragma pack(n)和该数据成员自身长度,比较小的那个进行
  • 结构(或联合)的整体对齐规则:数据成员对齐后,结构(或联合)整体也要进行对齐,对齐按照#pragma pack(n)和结构(联合)最大数据成员长度中,比较小的那个进行
  • 结构体作为成员:内部结构体成员从最大元素的整数倍和#pragma pack(n)最小的一个的整数倍地址开始存储。

例如:

struct SS {
     int a;
     char b;
     short c;
     int d;
     struct FF {
         int a1;
         char b1;
         short c1;
         char d1;
     } MyStructFF;
     int e;
     double ww; 
 } MyStructSS;

其内存对齐方式如下:

测试代码:

#include <iostream>
 /* #pragma pack(4) */
 using std::cout;
 using std::endl;
 struct x {
     char a;
     int b;
     short c;
     char d;
 } MyStructX;//12
 struct y {
     int b;
     char a;
     char d;
     short c;
 } MyStructY; // 8
 struct SS {
     int a;
     char b;
     short c;
     int d;
     struct FF {
         int a1;
         char b1;
         short c1;
         char d1;
     } MyStructFF;
 #if 1
     /* char e; // 28 */
     int e;
     double ww; // 40
 #endif
 } MyStructSS;
 struct DD {
     int a;
     char b;
     short c;
     int d;
     struct FF {
         double a1;
         char b1;
         short c1;
         char d1;
     } MyStructFF;
     char e; // 40
 } MyStructDD;
 struct GG {
     char e[2];
     short h;
     struct A {
         int a;
         double b;
         float c;
     } MyStructA;
 } MyStructGG; // 32
 int main(int argc, char **argv) {
     cout <<"sizeof(MyStructX) = " << sizeof(MyStructX) << endl;
     cout <<"sizeof(MyStructY) = " << sizeof(MyStructY) << endl;
     cout <<"sizeof(MyStructSS) = " << sizeof(MyStructSS) << endl;
     cout <<"sizeof(MyStructDD) = " << sizeof(MyStructDD) << endl;
     cout <<"sizeof(MyStructGG) = " << sizeof(MyStructGG) << endl;
     return 0;
 }


相关实践学习
简单用户画像分析
本场景主要介绍基于海量日志数据进行简单用户画像分析为背景,如何通过使用DataWorks完成数据采集 、加工数据、配置数据质量监控和数据可视化展现等任务。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
相关文章
|
16天前
|
运维 算法 安全
深入理解操作系统的内存管理:原理与实践
【4月更文挑战第25天】 在现代计算机系统中,操作系统扮演着至关重要的角色,它负责协调和管理硬件资源,为上层应用提供必要的服务。其中,内存管理是操作系统的核心功能之一,它不仅关乎系统性能,也直接影响到系统的稳定性和安全性。本文将深入探讨操作系统内存管理的关键原理,包括虚拟内存、物理内存分配、分页机制以及内存保护等,并结合Linux操作系统实例,分析其内存管理的实现细节。通过理论与实践的结合,旨在为读者提供一个全面、深入的操作系统内存管理视角。
|
18天前
|
算法 调度 UED
深入理解操作系统内存管理:原理与实践
【4月更文挑战第23天】 在现代计算机系统中,操作系统的内存管理是保证系统高效、稳定运行的关键组成部分。本文旨在深入探讨操作系统中内存管理的理论基础、关键技术以及实际操作过程,通过对内存分配策略、虚拟内存技术、分页与分段机制等核心概念的详细解析,为读者提供一个清晰、全面的内存管理视角。此外,文章还将通过案例分析,展示内存管理在解决实际问题中的应用,以期加深读者对操作系统内存管理复杂性的认识和理解。
|
1月前
|
算法 Java 内存技术
深入理解操作系统的内存管理:原理与实践
【4月更文挑战第8天】本文旨在深入探讨操作系统中内存管理的关键技术和实现细节。我们将从内存管理的基本原理出发,逐步解析操作系统如何通过各种策略和算法实现高效的内存分配、回收和保护。文章还将介绍一些常见的内存管理问题及其解决方案,帮助读者更好地理解和应对实际工作中可能遇到的挑战。
|
3天前
|
Arthas 监控 Java
JVM工作原理与实战(三十一):诊断内存泄漏的原因
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了诊断内存溢出的原因、MAT内存泄漏检测的原理等内容。
11 0
|
3天前
|
存储 Arthas 监控
JVM工作原理与实战(三十):堆内存状况的对比分析
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了堆内存状况的对比分析、产生内存溢出的原因等内容。
10 0
|
3天前
|
Arthas Prometheus 监控
JVM工作原理与实战(二十九):监控内存泄漏的工具
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了解决内存溢出的步骤、Top命令、VisualVM、Arthas、Prometheus + Grafana等内容。
10 0
|
3天前
|
监控 Java 测试技术
JVM工作原理与实战(二十八):内存溢出和内存泄漏
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了内存溢出与内存泄漏、内存泄漏的常见场景、解决内存溢出的步骤等内容。
JVM工作原理与实战(二十八):内存溢出和内存泄漏
|
4天前
|
监控 安全 Java
JVM工作原理与实战(二十一):内存管理
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了不同语言的内存管理(C/C++、Java)、垃圾回收的对比(自动垃圾回收与手动垃圾回收)等内容。
11 0
|
4天前
|
Arthas 存储 监控
JVM工作原理与实战(二十):直接内存
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了直接内存、在直接内存上创建数据等内容。
|
4天前
|
存储 监控 Java
JVM工作原理与实战(十七):运行时数据区-栈内存溢出
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了栈内存溢出、设置虚拟机栈的大小等内容。
11 0