操作系统 内存对齐

news2024/10/6 22:30:09

文章目录

    • 内存管理
    • 内存对齐
      • 为什么需要内存对齐
      • 内存对齐的规则
      • 举例说明
      • 两个函数

内存管理

  • 内存是计算机的重要组成部分,内存是与cpu沟通的桥梁,用来暂存cpu中的运算数据。在早期,程序直接运行在物理内存中,直接操作物理内存,导致内存的利用率较低,地址空间不隔离等问题,这就引入了虚拟内存的概念。
  • 虚拟内存是在程序和物理内存之间引入一个中间层,这个中间层就是虚拟内存。虚拟内存实现了对进程地址与物理地址的隔离
  • 在linux中,虚拟内存划分为用户空间和内核空间,用户进程只能访问用户空间的虚拟内存,而系统调用、外设中断或者异常等才可以访问内核空间。
  • 用户空间分为五个部分:代码段(存储可执行文件)、数据段(存储已经初始化的全局变量、静态变量)、BSS段(存储未初始化的全局变量)、堆区(动态分配的内存段)、栈区(临时创建的局部变量)
    在这里插入图片描述
  • 在计算机中,最小的存储单位是字节,理论上任意的地址都可以通过总线进行访问,每次寻址传输逇数据的大小与cpu的位数有关,常见的cpu的位数有8位,16位,32位,64位。位数越高,单次操作执行的数据量越大,性能越强。
  • 操作系统的位数一般与cpu的位数相匹配,32位的cpu可以寻址4GB的内存空间,也可以运行32位的操作系统,同样的,64位的cpu可以运行32位的操作系统,也可以运行64位的操作系统。

内存对齐

  • 按照理论上讲,对于任何变量的访问都是可以从任何地址开始访问,但实际上,访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按照一定规则排列,而不是简单的顺序排列,这就是内存对齐
  • 内存对齐说的是首地址对齐,而不是每个变量大小对齐
  • 内存对齐是为了方便计算机读写数据
  • 在c语言中,可以使用sizeof()去求取变量占用内存的大小

为什么需要内存对齐

首先需要明确,cpu是按照块来访问内存的,根据不同的平台,块的大小不同,通常是按照2的次方倍字节进行数据读取

在这里插入图片描述

对齐的地址一般都是n(n=2、4、8)的倍数

  1. 一个字节的变量,例如char,存放在任意地址的位置上
  2. 两个字节的变量,例如short,存放在2的整数倍的地址上
  3. 四个字节的变量,例如flaot、int,存放在4的整数倍地址上
  4. 八个字节的变量,例如long long、double,存放在8的整数倍的地址上

内存对齐的规则

  • 对于标准数据类型(内建数据类型),内存地址是该种数据类型的整数倍,如int类型,地址要是4字节的整数倍;

  • 对于非标准数据类型,比如结构体,由于结构体通常包含不同类型的数据,因此需要准守一定的规则

    • 结构体成员对齐,第一个结构体成员的应该放在偏移地址为0 的地方,往后的每个结构体成员需要从最小长度min_L的整数倍的地方开始存放。min_L通过是该数据类型的长度和计算机默认存储模式长度取最小值确定(比如32位机器中int型占4个字节,机器默认存储是8个字节,那么存储是按照4的整数倍进行,如果机器默认存储是2个字节,那么存储是按照2的整数倍进行)
    • 结构体的总大小,即sizeof() 的计算结果,是结构体内部占用最大字节的数据类型长度机器默认存储模式字节长度最小值整数倍,不足需要补齐。
    • 结构体嵌套时,如果结构体M中包含结构体N,还是按照最大字节成员类型大小对齐,但是结构体N的起点为N内部最大字节成员的整数倍(如,结构体M中嵌套结构体N,N中有int char 和double ,那么N应该从8的整数倍开始)
  • 对于数组成员:比如 char a[5],它的对齐方式和连续写 5 个 char 类型变量是一样的,也就是说它还是按一个字节对齐。

  • 含联合体成员:取联合体中最大类型的整数倍地址开始存储

举例说明

//假设默认存储8个字节//
typedef struct Student1{
	int a ;// 从4的倍数开始,0-3
	char b://从1的倍数开始,4(实际占用4-7)
	double c;//从8的倍数开始,8-15
	float d;//从4的倍数开始,16(16-19)
}Student1;
//结构体内部对齐后大小20个字节(0-19);整体对齐,要满足最大字节类型的整数倍,即8的整数倍,故为24,即sizeof(Student1)=24
//嵌套结构体
typedef struct Student2{
	char a ;// 从1的倍数开始,0(0-7)
	Student1 b://从内部成员最大字节整倍数开始,即从8开始存储,(占用第8-31字节)
	double c;//从8的倍数开始,即32-39
}Student2;
//结构体内部对齐后大小40个字节(0-19);整体对齐,要满足最大字节类型的整数倍,即8的整数倍,故为40,即sizeof(student)=40
//含有数组
struct stu1 {
    char a[18];//从1的倍数开始0-17(实际0-23)
    double b;//从8的倍数开始24-31
    char c;//从1的倍数开始32(实际32-35)
    int d;//从4的倍数开始36-39
    short e;//从2的倍数开始40-41
}//结构体对齐后占42个字节,整体对齐后满足最大类型的整数倍,即8的整数倍,所以sizeof(stu1)=48

结果展示:
在这里插入图片描述

struct stu1 {
    char a[18];//0-17(实际0-19)
    int b[3];//20-31
    short c;//32-33
    char d;//34,实际34-35
    int e;//36-39
    short f;//40-41
};
//结构体对齐后占41个字节,整体对齐满足最大类型的整数倍,即4的倍数,所以sizeof()=44

结果展示:
在这里插入图片描述

//枚举类型:4个字节
enum DAY {
    MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
struct stu1 {
    char a[5];//0-4
    char b[3];//5-7
    enum DAY day;//枚举类型占4个字节,4的倍数,8-11
    int *c;//linux64下指针占8个字节,8的倍数,16-23
    short d;//24-25
    int e;//28-31
};
//结构体对齐占32字节,sizeof是8的倍数也是32字节

结果展示:
在这里插入图片描述

//结构体嵌套
#include<stdio.h>
#include<stdlib.h>
typedef struct stu2 {
    char x;
    int y;
    double z;
    char v[6];
}stu2;//这里以8的倍数开始对齐
typedef struct stu1 {
    union u1 {
        int a1;
        char a2[5];
    }a;//联合体:取union中最大的一个变量类型的大小,这里是a2
    stu2 b;
    int c;
}stu1;

int main(){
        printf("%d\n",sizeof(stu1));//输出结果是40
        return 0;
}

结果展示:
在这里插入图片描述

struct stu2 {
    char x;
    int y;
    double z;
    char v[6];
};//以8的倍数来对齐
struct stu1 {
    char a;
    struct stu2 b;
    int c;
};//sizeof=40,sizeof是8的倍数

结果展示:
在这里插入图片描述

两个函数

attribute((packed)):取消变量对齐,按照实际占用字节数对齐(就是让变量之间排列紧密,不留缝隙)。(gcc才支持)

struct __attribute__((packed)) stu1 {    // 取消内存对齐
    char a;
    long b;
    short c;
    float d;
    int e;
};//占用19字节=1+8+2+4+4

结果展示:
在这里插入图片描述

#pragma pack (n):让变量强制按照 n 的倍数进行对齐,并会影响到结构体结尾地址的补齐(详见四的通常情况下关于结尾地址补齐的描述)。

#pragma pack (2)    // 强制以 2 的倍数进行对齐
struct stu1 {
    short a;
    int b;
    long c;//linux64中long占8个字节
    char d;
};//占用16字节
#pragma pack ()    // 取消强制对齐,恢复系统默认对齐

结果展示:
在这里插入图片描述

上面例子展示的都是以centos7,64位系统进行展示的


ps:各种操作系统基本类型所占大小

在这里插入图片描述

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

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

相关文章

MathType7.5最新版本升级教程

MathType7.5是MathType6.9a的升级版本&#xff0c;这是一款好用的数学公式编辑器&#xff0c;软件支持win、mac等操作系统&#xff0c;可以与各类办公软件兼容&#xff0c;能够快速在office文档中进行各类数学公式、符号的输入和运算等操作&#xff0c;coco玛奇朵小编为大家带来…

LiveGBS流媒体平台GB/T28181常见问题-如何禁用删除已注册设备国标设备如何删除

LiveGBS常见问题-如何禁用删除已注册设备国标设备如何删除 1、禁用删除设备2、找到需要删除的设备3、接入控制黑名单4、配置到黑名单5、删除设备6、搭建GB28181视频直播平台 1、禁用删除设备 有的时候&#xff0c;需要将接入到平台的某些设备禁用&#xff0c;并删除。改如何操…

池化技术在真实业务中的实践

一些废话 作为一名Java开发人员&#xff0c;池化技术或多或少在业务代码中使用。常见的包括线程池、连接池等。也是因为Java语言超级丰富的基建&#xff0c;基本上这些池化能力都有着相对成熟的“工具”。比如&#xff0c;需要使用线程池的时候常常会选择Spring提供的 ThreadP…

DL Homework 4

目录 1 整理一下理论收获 1.1 基础理论 1.2 应用到机器学习 1.3 参数学习 1.4 反向传播算法 2.激活函数 3.神经网络流程推导(包含正向传播和反向传播) 4.数值计算 - 手动计算 5.代码实现 - numpy手推 6.代码实现 - pytorch自动 7.激活函数Sigmoid用PyTorch自带函数torc…

蓝桥杯(七段码,C++)

思路&#xff1a; 1、把灯管的连接转为图结构&#xff0c;相邻的灯管即认为有边。 2、用深度搜索&#xff0c;去计算有多少种不同字符。 3、因为有每种字符都会重复算两遍&#xff0c;最后的结果需要数以2。 #include <iostream> using namespace std;int graph[7][7…

震惊!阿里卷成这样?不吃饭了,上厕所、团建都要聊工作,人均上厕所小于一天三次...

上一篇&#xff1a;雷军被小米封号 你敢相信吗&#xff1f;最近一篇名为《坐标阿里 我们组已经不吃饭了》的帖子在大厂社区上引发热议。 作者爆料&#xff1a;坐标阿里&#xff0c;组里已经卷到不吃饭了&#xff0c;之前卷到上厕所要聊工作、团建都要聊工作&#xff0c;现在已经…

B2R靶机渗透

B2R靶机渗透 视频参考&#xff1a;ajest &#xff1a;https://www.zhihu.com/zvideo/1547357583714775040?utm_id0 原文参考&#xff1a;ajest &#xff1a;https://www.zhihu.com/column/c_1403138803561816064 文章目录 B2R靶机渗透1 启动靶机&#xff0c;查看后网卡为ma…

数据特征选择 | Lasso特征选择(Python)

文章目录 效果一览文章概述源码设计小结效果一览 文章概述 Lasso算法是一种经典的线性回归算法,被广泛应用于特征选择和降维问题。相较于传统的线性回归算法,Lasso算法能够在保持预测准确性的同时,自动筛选出对目标变量影响较大的特征变量,从而达到降低模型复杂度、提高泛化…

CSS悬停卡片翻转明信片效果源码附注释

运行效果演示: HTML页面代码: <!DOCTYPE html> <html lang="en" > <head>

kafka安装步骤以及初步入门

安装Java sudo apt install default-jdk # 执行完直接直接查看版本就好了 java -versionhttps://blog.csdn.net/CyberSparkZ/article/details/132441191 安装zookeeper https://blog.csdn.net/supercrsky/article/details/124570611 https://blog.csdn.net/xiaozhang_man/ar…

为什么大多数企业开始转型做私域?

随着互联网的迅猛发展&#xff0c;越来越多的企业纷纷选择转型做私域电商。下面是十大理由&#xff0c;说明为什么大多数企业开始转型做私域。 一、提高用户黏性 通过私域化经营&#xff0c;企业能够更好地掌握用户信息和行为习惯&#xff0c;建立用户数据库&#xff0c;并利…

206、SpringBoot 整合 RabbitMQ 的自动配置类 和 对应的属性处理类 的知识点

目录 ★ Spring Boot 为 RabbitMQ 提供的自动配置▲ 自动配置类&#xff1a;RabbitAutoConfiguration▲ 属性处理类&#xff1a;RabbitProperties相关配置 ★ AmqpAdmin的方法★ AmqpTemplate的方法代码演示创建一个springboot的项目。application.properties 配置属性 ★ Spri…

JavaScript发布—订阅模式

JavaScript发布—订阅模式 1 什么是发布—订阅模式2 DOM 事件3 实现一个发布—订阅模式4 发布—订阅模式的通用实现5 取消订阅的事件6 全局的发布—订阅对象7 模块间通信 1 什么是发布—订阅模式 发布—订阅模式又叫观察者模式&#xff0c;它定义对象间的一种一对多的依赖关系…

第五十六章 学习常用技能 - 执行 SQL 查询

文章目录 第五十六章 学习常用技能 - 执行 SQL 查询执行 SQL 查询检查对象属性 第五十六章 学习常用技能 - 执行 SQL 查询 执行 SQL 查询 要运行 SQL 查询&#xff0c;请在管理门户中执行以下操作&#xff1a; 选择系统资源管理器 > SQL。如果需要&#xff0c;请选择标题…

Servlet与设计模式

1 过滤器和包装器 过滤器可以拦截请求及控制响应&#xff0c;而servlet对此毫无感知。过滤器有如下作用&#xff1a; 1&#xff09;请求过滤器&#xff1a;完成安全检查、重新格式化请求首部或体、建立请求审计日志。 2&#xff09;响应过滤器&#xff1a;压缩响应流、追加或…

softmax激活函数

Softmax激活函数是一种用于多类别分类问题的激活函数&#xff0c;通常用于神经网络的输出层。它将原始分数&#xff08;也称为logits&#xff09;转换为表示概率分布的数值&#xff0c;使得每个类别的概率值都在0和1之间&#xff0c;并且所有类别的概率之和等于1。这使得它适用…

2023年9月 青少年软件编程等级考试Scratch二级真题

202309 青少年软件编程等级考试Scratch二级真题&#xff08;电子学会等级考试&#xff09; 试卷总分数&#xff1a;100分 试卷及格分&#xff1a;60 分 考试时长&#xff1a;60 分钟 第 1 题 点击绿旗&#xff0c;运行程序后&#xff0c;舞台上的图形是?( ) A&#xff1a;画…

极简c++(8)抽象类与多态

类型转换规则 父类定义的指针可以指向子类对象&#xff1b; 指针会误以为&#xff0c;他们指向的对象是Base1类型&#xff0c;导致错误&#xff1b; 虚函数定义 多态 如何实现多态&#xff1a; 1.创建类的继承关系图 2.所以类对象都可以调用的这个函数 3.创建父类指针数组 …

PyTorch 深度学习之卷积神经网络(高级篇)Advanced CNN(十)

0. Revision 前面讲的比较简单的是 串行网络结构 1. GoogLeNet 1.1 Inception module w h 要一致 what is 11 convolution? 信息融合-eg.高中各门学科成绩比较(总分) 最主要工作:改变通道数量 why is 11 convolution? 减少10倍 1.2 implementation of inception module 拼…