精华内容
下载资源
问答
  • 网上有很多关于内存对齐问题的博客,本文仅分享一下实际案例,包括使用Excel形象化分析内存对齐问题的方法以及相对应的c语言验证小程序,希望能帮到读者去理解内存对齐


    案例背景

    笔者小白一枚,在开发LogViewer工具时,遇到了内存对齐的问题。网上有很多关于内存对齐问题的博客,本文仅分享一下实际案例,希望能帮到读者去理解内存对齐。
    LogViewer是一款自研的协议栈信令解析工具,协议栈通过TCP将信令上传给LogViewer进行解析(信令本质上就是C语言中的结构体)。笔者所接触的4G协议栈是基于x86系统开发的,而5G协议栈是基于x64系统开发的。因此,5G协议栈结构体的存储默认是8字节对齐的,而LogViewer在没有更改配置的情况下依旧按照4字节对齐去解析,于是导致数据异常
    为了方便阐述内存对齐的问题,笔者将具体信令抽象成如下MEM_ALIGN_DEMO_T结构体,读者可忽略信令及其内容的实际意义。

    typedef struct mem_align_demo_t
    {
            unsigned short  A;      // 2bytes
            unsigned short  B;      // 2bytes
            unsigned long   C;      // 8bytes
            unsigned long   D;      // 8bytes
            unsigned char   E;      // 1bytes
    }MEM_ALIGN_DEMO_T;
    

    案例分析

    (1) 利用Excel形象化内存对齐问题

    闲言少叙,直接上图。建议读者遇到内存对齐问题时,可以利用Excel将数据的存储和解析过程形象化。下面对图示几个部分做具体的说明:

    • 原始数据
      原始数据,即MEM_ALIGN_DEMO_T结构体各成员的原始数据,包括A->E共5个成员,其类型和数据在下图中一目了然。例如A=0x0208,占2个字节,以此类推。
    • 8字节对齐存储
      8字节对齐存储,即MEM_ALIGN_DEMO_T结构体以8字节对齐形式存入内存后的实际数据。图示1->8表示同一字节的Bit位序列,1->32表示不同字节各自的内存地址序列。需要注意如下几点:
      【1】黄色区域是8字节对齐时自动补齐占位的字节,并且其值是不确定的,之所以图示中全部为零,是因为提前将MEM_ALIGN_DEMO_T结构体内存全部置0了。读者可以使用下文中的C程序进行验证,如果不将结构体内存全部置0,每次执行时,黄色区域的值是不一样的。
      【2】8字节对齐,可以简单的理解成以8个字节为一个基本单元进行存储。比如,以图示1->8和9->16这两个基本元为例进行说明。A=0x0208占2字节,直接存入1->2两个字节即可;B=0x001C占2字节,接着A后面存入3->4两个字节即可;当继续存储C=0x00062F8100002A00的时候,第一个基本单元(1->8字节)只剩下4个字节了,不能存储占8个字节的C,所以C要放到下一个基本单元(9->16)存储,而第一个基本单元中的后4个字节(5->8)只起到占位补齐的作用。同理E后面的7个字节(25->32)也是占位补齐。
      【3】细心的读者会发现,为什么存入内存后的字节是反的。比如说A=0x0208,存入内存后,变成了0x0802。这就涉及到大端模式和小端模式的问题,不是本文讨论的重点。大端模式指数据的高字节保存在内存的低地址,小端模式指数据的高字节保存在内存的高地址,笔者的系统是小端模式。
    • 4字节对齐解析
      4字节对齐解析,即以4字节对齐方式解析8字节对齐存储的结构体数据,部分数据就会面目全非。其中橙色部分的数据就会被舍弃,具体解析结果见解析数据部分。
    • 解析数据
      解析数据,即以4字节对齐方式解析之后的MEM_ALIGN_DEMO_T结构体各成员的实际数据。A和B未受影响,正好共同占用了4个字节,而解析C数据时会将补齐占位的5->8字节也当成C的数据部分,于是C、D、E数据都会发生错误,分别变成了0x00002A0000000000、0x000029E300062F81、0x81。
      利用Excel形象化内存对齐问题

    (2) 简单的C程序验证内存对齐问题

    笔者做了一个简单的c程序mem_align.c,该程序实现MEM_ALIGN_DEMO_T结构体成员的value、addr、size的打印,并且以16进制输出实际存储在内存中的结构体数据,读者可以在此基础上进行验证和学习。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct mem_align_demo_t
    {
            unsigned short	A;	// 2bytes
            unsigned short 	B;	// 2bytes
            unsigned long 	C; 	// 8bytes
    		unsigned long 	D;	// 8bytes
    		unsigned char 	E;	// 1bytes
    }MEM_ALIGN_DEMO_T;
    
    int main()
    {
    	unsigned char	*buffer	= NULL;
    	unsigned int 	i 		= 0;
    
    	/** Define and print struct */
    	MEM_ALIGN_DEMO_T		t;
    	memset(&t, 0, sizeof(t));
    	t.A = 0x0208;
    	t.B = 0x001c;
    	t.C = 0x00062f8100002a00;
    	t.D = 0x00062f81000029e3;
    	t.E = 0x02;
    
    	printf("=================================================================\n");
    	printf("\tvalue\t\t\taddr\t\t\tsize\n");
    	printf("t.A\t%04x\t\t\t%p\t\t%ld\n", t.A, &(t.A), sizeof(t.A));
    	printf("t.B\t%04x\t\t\t%p\t\t%ld\n", t.B, &(t.B), sizeof(t.B));
    	printf("t.C\t%016lx\t%p\t\t%ld\n", t.C, &(t.C), sizeof(t.C));
    	printf("t.D\t%016lx\t%p\t\t%ld\n", t.D, &(t.D), sizeof(t.D));
    	printf("t.E\t%02x\t\t\t%p\t\t%ld\n", t.E, &(t.E), sizeof(t.E));
    	printf("t\t--\t\t\t%p\t\t%ld\n", &t, sizeof(t));
    	printf("=================================================================\n");
    
    	/** Output actual stored struct content in hex */
    	buffer = (unsigned char *)malloc(sizeof(t));
    	memcpy(buffer, (unsigned char *)(&t), sizeof(t));
    	printf("Actual Struct Content:\n");
    	for (i=0; i<sizeof(t); i++)
    	{
    		printf("%02x", *(buffer + i));
    	}
    	printf("\n");
    	printf("=================================================================\n");
       	free(buffer);
    
    	return 1;
    }
    

    创建mem_align.c文件,将代码复制下来保存(笔者系统ubuntu18.04.3-x64,gcc版本7.5.0)。
    编译:gcc -Wall -g mem_align.c -o mem_align
    执行:./mem_align
    输出结果如下,注意观察各成员的内存地址addr的变化,请读者自行和上述Excel表格对应分析,不做赘述。另外,整个结构体的大小为32字节,而不是2+2+8+8+1=21个字节,自然是因为8字节对齐时补齐占位造成的。

    root@ubuntu:/home/share/study# gcc -Wall -g mem_align.c -o mem_align
    root@ubuntu:/home/share/study# ./mem_align 
    =================================================================
    		value				addr				size
    t.A		0208				0x7ffde716fac0		2
    t.B		001c				0x7ffde716fac2		2
    t.C		00062f8100002a00	0x7ffde716fac8		8
    t.D		00062f81000029e3	0x7ffde716fad0		8
    t.E		02					0x7ffde716fad8		1
    t		--					0x7ffde716fac0		32
    =================================================================
    Actual Struct Content:
    08021c0000000000002a0000812f0600e3290000812f06000200000000000000
    =================================================================
    root@ubuntu:/home/share/study# 
    

    总结说明

    1. 网上有很多关于内存对齐问题的博客,本文仅提供一个实际案例供读者参考学习。另外,强烈推荐使用Excel表格的方式去分析内存对齐问题。
    2. 笔者小白一枚,此文档仅用于学习记录和交流,如能帮助到读者倍感荣幸。
    展开全文
  • 内存对齐问题

    2011-09-16 16:27:03
    最近在调试中遇到点内存对齐...不论是C、C++对于内存对齐的问题在原理上是一致的,对齐的原因和表现,简单总结一下,以便朋友们共享。 一、内存对齐的原因 大部分的参考资料都是如是说的: 1、平台原因(移植原因)
     
    

    最近在调试中遇到点内存对齐的问题,别人问我是怎么回事,我赶紧偷偷查了一下,记录下来。

    不论是C、C++对于内存对齐的问题在原理上是一致的,对齐的原因和表现,简单总结一下,以便朋友们共享。

    一、内存对齐的原因
    大部分的参考资料都是如是说的:
    1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
    2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

    也有的朋友说,内存对齐出于对读取的效率和数据的安全的考虑,我觉得也有一定的道理。

    二、对齐规则
        每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。比如32位windows平台下,VC默认是按照8bytes对齐的(VC->Project->settings->c/c++->Code Generation中的truct member alignment 值默认是8),程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

        在嵌入式环境下,对齐往往与数据类型有关,特别是C编译器对缺省的结构成员自然对届条件为“N字节对齐”,N即该成员数据类型的长度。如int型成员的自然对界条件为4字节对齐,而double类型的结构成员的自然对界条件为8字节对齐。若该成员的起始偏移不位于该成员的“默认自然对界条件”上,则在前一个节面后面添加适当个数的空字节。C编译器缺省的结构整体的自然对界条件为:该结构所有成员中要求的最大自然对界条件。若结构体各成员长度之和不为“结构整体自然对界条件的整数倍,则在最后一个成员后填充空字节。

        那么可以得到如下的小结:

    类型 对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
    Char    偏移量必须为sizeof(char)即1的倍数
    Short   偏移量必须为sizeof(short)即2的倍数
    int     偏移量必须为sizeof(int)即4的倍数
    float   偏移量必须为sizeof(float)即4的倍数
    double  偏移量必须为sizeof(double)即8的倍数

       各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节编译器会自动填充。同时为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节,也就是说:结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。对于char数组,字节宽度仍然认为为1。

       对于下述的一个结构体,其对齐方式为:

    struct Node1{

        double m1;
        char m2;
        int m3;
    };

      对于第一个变量m1,sizeof(double)=8个字节;接下来为第二个成员m2分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为8,是sizeof(char)的倍数,所以把m2存放在偏移量为8的地方满足对齐方式,该成员变量占用 sizeof(char)=1个字节;接下来为第三个成员m3分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为9,不是sizeof (int)=4的倍数,为了满足对齐方式对偏移量的约束问题,自动填充3个字节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为12,刚好是sizeof(int), 由于8+4+4 = 16恰好是结构体中最大空间类型double(8)的倍数,所以sizeof(Node1) =16.

     

    typedef struct{

        char a;

        int b;

        char c;

    }Node2;

        成员a占一个字节,所以a放在了第1位的位置;由于第二个变量b占4个字节,为保证起始位置是4(sizeof(b))的倍数,所以需要在a后面填充3个字节,也就是b放在了从第5位到第8位的位置,然后就是c放在了9的位置,此时4+4+1=9。接下来考虑字节边界数,9并不是最大空间类型int(4)的倍数,应该取大于9且是4的的最小整数12,所以sizeof(Node2) = 12.
    typedef struct{

        char a;

        char b;

        int c;

    }Node3;

       明显地:sizeof(Node3) = 8

       对于结构体A中包含结构体B的情况,将结构体A中的结构体成员B中的最宽的数据类型作为该结构体成员B的数据宽度,同时结构体成员B必须满足上述对齐的规定。

       要注意在VC中有一个对齐系数的概念,若设置了对齐系数,那么上述描述的对齐方式,则不适合。

       例如:

    1字节对齐(#pragma pack(1))
    输出结果:sizeof(struct test_t) = 8 [两个编译器输出一致]
    分析过程:
    成员数据对齐
    #pragma pack(1)
    struct test_t {
        int a; 
        char b; 
        short c;
        char d; 
    };
    #pragma pack()
    成员总大小=8;

     

    2字节对齐(#pragma pack(2))
    输出结果:sizeof(struct test_t) = 10 [两个编译器输出一致]
    分析过程:
    成员数据对齐
    #pragma pack(2)
    struct test_t {
        int a; 
        char b; 
        short c;
        char d; 
    };
    #pragma pack()
    成员总大小=9;

     

    4字节对齐(#pragma pack(4))
    输出结果:sizeof(struct test_t) = 12 [两个编译器输出一致]
    分析过程:
    1) 成员数据对齐
    #pragma pack(4)
    struct test_t { //按几对齐, 偏移量为后边第一个取模为零的。
    int a; 
    char b; 
    short c;
    char d; 
    };
    #pragma pack()
    成员总大小=9;

     

    8字节对齐(#pragma pack(8))
    输出结果:sizeof(struct test_t) = 12 [两个编译器输出一致]
    分析过程:
    成员数据对齐
    #pragma pack(8)
    struct test_t {
    int a; 
    char b; 
    short c;
    char d; 
    };
    #pragma pack()
    成员总大小=9;

     

    16字节对齐(#pragma pack(16))
    输出结果:sizeof(struct test_t) = 12 [两个编译器输出一致]
    分析过程:
    1) 成员数据对齐
    #pragma pack(16)
    struct test_t {
    int a; 
    char b; 
    short c;
    char d; 
    };
    #pragma pack()
    成员总大小=9;

     

    至于8字节对齐和16字节对齐,我觉得这两个例子取得不好,没有太大的参考意义。

    展开全文
  • 先上一张图,如有侵权麻烦告知;这张图描述了不同存储介质的存取速度: 寄存器>...我们一直会听到"内存对齐"这一名词,但是不清楚为什么内存需要对齐.好像就是一个默认的定理,只管拿来用,确不懂该如何证明..

    先上一张图,如有侵权麻烦告知;这张图描述了不同存储介质的存取速度:

    寄存器>>cache(l1/l2/l3)>>ram>>flash>>硬盘>>网络存储.

    由于cpu的速度要远快于存储介质的读写速度,且存在不同类型的存储介质,受他们的体积,成本,效率等因素的影响,产生了我们今天用到的计算机的存储结构.

    内存对齐

    前言

    我们一直会听到"内存对齐"这一名词,但是不清楚为什么内存需要对齐.好像就是一个默认的定理,只管拿来用,确不懂该如何证明.最好的办法,就是从芯片最底层的工作原理去搞明白为什么要"内存对齐".

    接着会讲述结构体"struct"的内存对齐.当然这只是我的个人理解,如有错误还请帮忙指正,以免误导他人.

    以32位系统为例,它的"地址总线"和"数据总线"都是32位.

    一般的我们程序运行时的变量都是存储在ram中的,我们今天就从ram的角度去看为什么要"内存对齐".

    正文

    我们知道cpu的速度是很快的,ram的读写速度较慢,这样就会有点拉跨.那么32bits的数据总线在从ram中读数据的时候我们当然是希望尽量一次多读一点了,毕竟我们有32bit的宽度.假如每次只读一个存储单位也就是8bits,这样也未免浪费"数据总线"的宽度,而且也会使cpu不高兴.这样的话ram的4个存储单元就需要并行工作,也就是不管每次你问我要多少数据我每次都给你32bits数据(实际上ram的工作原理比这复杂的多,详情还需要自行研究).那么ram每次都传输32bits数据,也就是说它传输的基本单位为4bytes.

    接着想除了内存一般还需要访问寄存器(cache line和flash,硬盘不在我们的讨论之列,cache line一般都是32bytes或者64bytes之多,flash,硬盘之类的访问方式差异更大,譬如按页读,按块擦除,内存卷等概念),那32位机器上我们的寄存器都是32bit位宽的,这样操作效率最高.

    字节对齐的使用,这里举一个例子:

    我们在学C语言的时候有讲到过结构体的内存对齐,譬如对于下面一个结构:

    struct test {
        char a;
        int b;
    };

    如果没有采用内存对齐:

    a占一个字节, b占4个字节.假如没有内存对齐这一说.当程序访问这一结构体变量时,变量位于物理内存中.那么假设a占据内存地址0,b则占据内存地址1~4.由于ram访问是每次读4bytes,那么我们想要访问b的时候,需要先读地址0~3,再读地址4~7,然后把地址1~3和地址4处的值拼出变量b的值放到寄存器里.这样在没有内存对齐的情况下,我们需要读两次内存,并且还需要进行相应的转换.

    采用内存对齐:

    那么如果我们采用内存对齐呢,编译的时候编译器给a分配0~3的地址,b分配4~7的地址,这样我们想要读b的值时,只需要读一次地址4~7就可以了.是不是节省了很多的cpu指令周期呀.

    注意一点:

    这里结构体内存对齐是在编译阶段确定的,编译器在分配内存地址的时候做了对齐.那么我们知道编译器影响到的是虚拟地址,而我们读内存读的是物理地址啊.了解过linux页表机制的同学都知道,内存页一般都是4kBytes大小,虚拟内存的低12位(4kBytes)是页内的偏移地址,剩余的高几位才是用来映射物理页帧(page frame,得到该地址在物理内存的哪一页).也就是说虚拟内存的低12位和物理内存的低12位是对应的.所以这里我们讲内存对齐时用到的地址概念,无所谓是虚拟地址还是物理地址.

     

    Cahche Line伪共享

    我们知道为了解决ram的速度拉跨cpu的问题,出现了cache这一存储介质,由于它的成本原因以及体积原因,所以它的结构被做的比较巧妙,但是对于我们学习者来说,就显得复杂了.这里默认大家都有cache的相关概念.

    单核cpu下的伪共享:

    以32bytes大小的"Cache Line"为例:

    struct test1 {
        int a;
        int b;
    };

    a和b各占4bytes,假设a占据地址0~3,b占据地址4~7.当我们访问a的时候,会把地址0~31的数据加载到一条cache line中.当我们更新b中的数据时,cache line会变为invalid;下一次我们再要访问的时候需要重新加载cache line.

    如果我会经常读a中的数据,经常更新b中的数据,那么更新b会导致cache line的效率下降,因为我每次访问a的时候,只要在这之前cache line被b给更新了,那么我就得重新加载cache line.

    如果我们在a和b之间插入一些pad,使他们放在两条不同的cache line中,就可以避免了.譬如:

    struct test2 {
        int a;
        int c[7]; //padding
        int b;
    };

    或者你也可以测试一下下面的程序(注意运行时间可能收系统loading波动的影响,存在波动,可能会存在伪共享耗时更少的现象)

    #include <stdio.h>
    #include <sys/time.h>
    
    struct test1 {
    	volatile int a;
    	volatile int b;
    };
    
    struct test2 {
    	volatile int a;
    	volatile int c[7];
    	volatile int b;
    };
    
    int main(int argc, char *argv[])
    {
    	int epoch_tm = 0;
    	struct timeval tm;
    	int current_tm = 0;
    	int i;
    	struct test1 value1;
    	struct test2 value2;
    	int tmp;
    
    	gettimeofday(&tm, NULL);
    	current_tm = tm.tv_sec * 1000000 + tm.tv_usec;
    
    	for (i = 0; i < 1000000000; i++) {
    		tmp = value1.a;
    		value1.b = i;
    	}
    
    	gettimeofday(&tm, NULL);
    	epoch_tm = (tm.tv_sec * 1000000 + tm.tv_usec) -
    			current_tm;
    	printf("cache phony share cost [%d] usec\n", epoch_tm);
    
    	gettimeofday(&tm, NULL);
    	current_tm = tm.tv_sec * 1000000 + tm.tv_usec;
    
    	for (i = 0; i < 1000000000; i++) {
    		tmp = value2.a;
    		value2.b = i;
    	}
    
    	gettimeofday(&tm, NULL);
    	epoch_tm = (tm.tv_sec * 1000000 + tm.tv_usec) -
    			current_tm;
    	printf("cache not share cost [%d] usec\n", epoch_tm);
    }

    多核CPU下的伪共享:

    我也是看的其他人的文章,简单做个记录吧.这个是说,多核CPU的每个核都有自己的cache设备,根据cache的一致性协议.多核的cache line是保持一致的,假如A核的某一cache line变成invalid的了,那么其它核的该cache line也是invalid状态.解决的办法应该也是加pad吧,跟前面讲的差不多.不对的还望大佬们教育.谢谢~~

    展开全文
  • 内存栅栏和内存对齐

    2016-04-05 18:07:35
    Cache 一致性问题单核 Cache 中每个 Cache line 有2个标志:dirty 和 valid 标志,它们很好的描述了 Cache 和 Memory 之间的数据关系(数据是否有效,数据是否被修改),而在多核处理器中,多个核会共享一些数据。...



     
    Cache 一致性问题
    单核 Cache 中每个 Cache line 有2个标志:dirty 和 valid 标志,它们很好的描述了 Cache 和 Memory 之间的数据关系(数据是否有效,数据是否被修改),而在多核处理器中,多个核会共享一些数据。



     
    只有 Core 0 访问变量 x,它的 Cache line 数据和内存中的数据一致,数据只存在于本 Cache 中。



     
    3个 Core 都访问变量 x,它们对应的 Cache line 数据和内存中的数据一致,数据存在于很多 Cache 中。



     

    Core 0 修改了x的值之后,这个 Cache line 数据被修改了,和内存中的数据不一致,数据只存在于本 Cache 中。其他 Core 对应的 Cache line 数据无效。



     
    内存栅栏
    简单来说,内存栅栏(Memory Barrier)就是从本地或工作内存到主存之间的拷贝动作。


     
    仅当写操作线程先跨越内存栅栏而读线程后跨越内存栅栏的情况下,写操作线程所做的变更才对其他线程可见。关键字 synchronized 和 volatile 都强制规定了所有的变更必须全局可见,该特性有助于跨越内存边界动作的发生,无论是有意为之还是无心插柳。
    在程序运行过程中,所有的变更会先在寄存器或本地 cache 中完成,然后才会被拷贝到主存以跨越内存栅栏。此种跨越序列或顺序称为 happens-before。
    写操作必须要 happens-before 读操作,即写线程需要在所有读线程跨越内存栅栏之前完成自己的跨越动作,其所做的变更才能对其他线程可见。


    内存对齐
    为何要内存对齐?
    1. 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
    2. 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。



     
    这是普通程序员心目中的内存印象,由一个个的字节组成,而 CPU 并不是这么看待的。


     
    CPU 把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此 CPU 在读取内存时是一块一块进行读取的。块大小成为 memory accessgranularity(粒度)本人把它翻译为&quot;内存读取粒度&quot;。
    假设CPU要读取一个int型4字节大小的数据到寄存器中,分两种情况讨论:
    1. 数据从0字节开始



     
    2. 数据从1字节开始
    再次假设内存读取粒度为4。



     
    当该数据是从0字节开始时,CPU 只需读取内存一次即可把这4字节的数据完全读取到寄存器中。
    当该数据是从1字节开始时,问题变的有些复杂,此时该 int 型数据不是位于内存读取边界上,这就是一类内存未对齐的数据。

    此时 CPU 先访问一次内存,读取0—3字节的数据进寄存器,并再次读取4—5字节的数据进寄存器,接着把0字节和6,7,8字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器。对一个内存未对齐的数据进行了这么多额外的操作,大大降低了 CPU 性能。
    这还属于乐观情况了,上文提到内存对齐的作用之一为平台的移植原因,因为以上操作只有有部分 CPU 肯干,其他一部分 CPU 遇到未对齐边界就直接*罢*工*了。

     

    展开全文
  • 当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union)。在C Programming Language 一书中对于联合体是这么描述的: 1)联合体是一个结构; 2)它的所有成员相对于基地址的偏移量都为0; 3)...
  • 当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union)。在C Programming Language 一书中对于联合体是这么描述的:      1)联合体是一个结构;      ...
  • 引入了大量把顺序存储空间的内容强制转换为结构体定义的格式进行读取的操作,结果发现有些值读取错误,求教在intel公司工作的大侠,才得知是内存对齐的问题,恍然大悟,特转载大侠推荐的文章共享。   <br...
  • 结构体和共用体(内存对齐原则)

    千次阅读 2018-11-22 21:00:19
    共用体:共用体(union)把几种不同数据类型的变量存放在同一块内存里,共用体中的变量共享同一块内存,后赋值的会覆盖重写前面内存空间。共用体变量所占内存的长度为定义时的最长成员的长度。 关键字:union。 ...
  • <br />这天在网上搜索关于内存对齐的资料,搜到一篇相关的文章,是一个毕业不久的大学生写的 本来我打算搜索一些资料,自己总结一下的,但我觉得这篇文章已经总结的很好了,故认真阅读了一番,获益匪浅...
  • 大端小端 小端存储:数据的低字节存储在地址空间的低字节位,数据的高字节存储在地址空间的高字节位。...2、跟据联合体特点,所有成员共享内存空间。 特别的:网络字节序是大端模式。 #include <s
  • size:共享内存的大小以兆对齐 flag:打开队列的方式,一般为IPC_CREAT (2)shmat 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1。——映射共享内存 man手册:man 2 shmat shmid:共享...
  • 了解数据在共享内存中是如何被安排的 掌握从二维共享内存到线性全局内存的索引转换 解决不同访问模式中存储体中的冲突 在共享内存中缓存数据以减少对全局内存的访问 使用共享内存避免非合并全局内存的访问 ...
  • 上一次看到CSDN上讨论内存对齐问题,当时想这个现在已经不太需要讨论了,已经由CPU解决了。当时上一次,我考虑一道位图旋转问题的时候想到了这个问题。下面把位图旋转的解决方法贴出来与大家共享:void ...
  • 内存对齐讨论想到位图旋转上一次看到CSDN上讨论内存对齐问题,当时想这个现在已经不太需要讨论了,已经由CPU解决了。当时上一次,我考虑一道位图旋转问题的时候想到了这个问题。下面把位图旋转的解决方法贴出来与...
  • 函数说明shmgetint shmget(key_t key...当key设置为IPC_PRIVATE或者不存在重复key shmflg 设置成IPC_CREATE的情况下,一个新的共享内存段被创建,分配的长度等于参数size并且和PAGE_SIZE对齐。 如果shmflg指定IPC_CREA
  • /*查看电脑大小端 * 大端:低地址存储低位,小端:低地址存储高位 *.../* 联合体的成员变量是共享空间的,其空间大小由最大成员变量决定; */void show1(){ union A{ int a; char c[4]; }; struct B{ int a; 
  • CUDA学习笔记(十二)共享内存

    千次阅读 2018-07-21 08:12:07
    在global Memory部分,数据对齐和连续是很重要的话题,当使用L1的时候,对齐问题可以忽略,但是非连续的获取内存依然会降低性能。依赖于算法本质,某些情况下,非连续访问是不可避免的。使用shared memory是另一种...
  • 二、内存对齐 三、字节顺序 四、数据结构 五、并发控制 六、关键代码 内存映射类MappedFile 数据结构类Queue 元数据类Metadata 数据块类Block 块标识类ACK 七、互斥原理 github项目地址:...
  • 2. Memory(内部存储器):内存,又称主存,临时存放CPU的运算数据,以及与硬盘等外部存储器交换的数据,它是CPU能直接寻址的存储空间,由半导体器件制成。特点是存取速率快。 3. IO(输入/输出)设备:比如显示器,...
  • 在 上一篇文章 中,我研究了如何将一组线程访问的全局内存合并到一个事务中,以及对齐和跨步如何影响 CUDA 各代硬件的合并。对于最新版本的 CUDA ...但是,在这种情况下,如果我们使用共享内存,就可以合并内存访...
  • 030-JVM-Cache Line、缓存对齐、伪共享

    千次阅读 2021-01-02 16:24:14
    由于寄存器的速度是非常快的,是内存的100被,是硬盘的10的六次方倍。 下图是个硬件的速度指标,可以使我们对其有更为直观的认识: 从cpu到 大约需要cpu周期 大约小的时间 主存(内存) 60-80ns QPI总线...
  • 寄存器速度最快,离CPU最近,成本最高,所以个数容量有限,其次是高速缓存(缓存也是分级,有L1,L2,L3等缓存),再次是主存(普通内存),然后是本地磁盘,最次是远程文件存储。 存储器层次结构 缓存 ...
  • C++ 字节对齐规则

    2020-09-21 22:30:22
    C++ 字节对齐规则 ...静态成员变量不占内存(存储在全局变量区,类共享) 样例 所有代码都是在VS的编译结果 #include<iostream> #include<algorithm> using namespace std; class a { int i; char c
  • 存储器层次结构 缓存行 缓存行是为了执行的更快。intel 的缓存行大小是64字节。...伪共享:如果,x,y 在一起。为了提高效率,会一起读...cpu为了提高指令效率,会在一条指令执行过程中(比如去内存读数据(慢100倍
  • jvm缓存行对齐

    2021-04-08 23:48:02
    文章目录1、cpu缓存结构2、伪共享问题3、缓存行对齐4、Disruptor框架 1、cpu缓存结构   cpu内核的缓存一般分为一级缓存和二级缓存,三级缓存。cpu运行时,先从一级缓存读取数据,如果读取失败,则从二级缓存读取,...
  • c++对象的内存模型

    2020-02-29 10:06:14
    直接抛结论:编译器将成员变量和成员函数分开存储,...而对象中同样存在内存对齐,这与结构体类似。 以下为例:创建的Student stu对象的大小为12字节(内存对齐) class Student{ private: char m_name; int m...

空空如也

空空如也

1 2 3 4 5 ... 15
收藏数 281
精华内容 112
关键字:

共享内存对齐