C++11:25內存對齊


25、內存對齊

0、課前秀

1、內存對齊介紹

  • 內存對齊(字節對齊):是一個數據類型所能存放的內存地址的屬性。當我們說一個數據類型的內存對齊為8時,就是指這個數據類型所定義出來的所有變量的內存地址都是8的倍數。
  • 當一個基本數據類型(Fundamental Types)的對齊屬性和這個數據類型的大小相等時,這種對齊方式稱為自然對齊(Naturally Aligned)
  • 對於結構體而言,默認的對齊將等於其中最大的成員的對齊值。

2、堆內存的內存對齊

  • 實際上,malloc一般使用當前平台默認的最大內存對齊數對齊內存。
  • 當我們需要分配一塊具有特定內存對齊的內存塊時,在MSVC下應當使用_aligned_malloc,而在gcc下一般使用memalign等函數。
  • aligned_malloc的實現.cpp
#include<assert.h>
inline void* aligned_malloc(size_t size, size_t alignment)
{
    //檢查alignment是否是2的N次方
    assert(!(alignment & (alignment - 1)));
    //計算出一個最大的offset,sizeof(void*)是為了存儲原始指針地址
    size_t offset = sizeof(void*) + (--alignment);
    
    //分配一塊帶offset的內存
    char* p = static_cast<char*>(malloc(offset + size));
    if(!p) return nullptr;
    
    //通過"&(~alignment)"把多計算的offset減掉
    void* r = reinterpret_cast<void*>(reinterpret_cast<size_t>(p + offset) & (~alignment));
    
    //將r當作一個指向void*的指針,在r當前地址前面放入原始地址
    static_cast<void**>(r)[-1] = p;
    //返回經過對齊的內存地址
    return r;
}

inline void aligned_free(void* p)
{
    //還原加原始地址,並free
    free(static_cast<void**>(p)[-1]);
}

3、利用alignas指定內存對齊大小

  • 使用代碼
alignas(32) long long a = 0;

#define XX 1
struct alignas(XX) MyStruct_1 {}; //OK

template <size_t YY = 1>
struct alignas(YY) MyStruct_2 {}; //OK

static const unsigned ZZ = 1;
struct alignas(ZZ) MyStruct_3 {}; //OK
  • alignas只能改大不能改小,改小仍然需要使用#pragma pack

4、利用alignof和std::alignment_of獲取內存對齊大小

  • alignof用來獲取內存對齊大小,用法如下:
MyStruct xx;
std::cout << alignof(xx) << std::endl;
std::cout << alignof(MyStruct) << std::endl;
  • std::alignment_of的功能是編譯期計算類型的大內存對齊。例子
struct MyStruct
{
    char a;
    int b;
    double c;
};

int main()
{
    int alignsize = std::alignment_of<MyStruct>::value;//8
    int sz = alignof(MyStruct);//8
    
    return 0;
}

5、內存對齊的類型std::aligned_storage

  • std::aligned_storage可以看成一個內存對齊的緩沖區,它的原型如下:template<std::size_t Len, std::size_t Align = /*default-alignment*/> struct aligned_storage;
  • std::aligned_storage一般和placement new結合使用,它的基本用法如下:
#include <iostream>
#include <type_traits>

struct A
{
    int avg;
    A(int a, int b):avg((a+b)/2){}
};

typedef std::aligned_storage<sizeof(A),alignof(A)>::type Aligned_A;

int main()
{
    Aligned_A a,b;
    new (&a) A(10,20);
    b = a;
    std::cout << reinterpret_cast<A&>(b).avg << std::endl;
    return 0;
}

6、std::max_align_t和std::align操作符

  • std::max_align_t用來返回當前平台的最大默認內存對齊類型。
  • 用如下方式獲得當前平台的最大默認內存對齊數:std::cout << alignof(std::max_align_t) << std::endl;
  • std::align用來在一大塊內存當中獲取一個符合指定內存要求的地址,例子如下:
char buffer[] = "-------------";
void* pt = buffer;
std::size_t space = sizeof(buffer) - 1;
std::align(alignof(int), sizeof(char), pt, space);

ReadMe

  • 20200514開了個頭,20200526白天看完,整理一波,也沒感覺到使用場景在哪,先把知識點記下再說吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM