Boost库学习笔记(三)内存对齐模块
一、模块简介
Boost.Align本模块主要的功能是提供一系列的函数、类、模板、特性和宏等来控制、审查和诊断内存对齐。
二、基本原理
1. 动态分配
C++11为class类型添加了增长对齐类型(over-alignment),但是C++标准库中的new运算符、表达式和默认的分配器、std::allocator并不支持为over-aligned的数据动态分配内存。boost提供库来提供函数和分配器来支持over-aligned的数据。
aligned_free(pointer)
代替了::operator delete(pointer, std::nothrow)
aligned_allocator<T>
代替了std::allocator<T>
aligned_allocator_adaptor<Allocator>
代替了 Allocator的使用
aligned_delete
代替了std::default_delete<T>
2. 指针对齐
C++11标准提供了std::align
来对齐指针的值,但是(libstdc++直到gcc4.8.0)并没有支持实现,msvc11.0错误的实现了它,Boost库实现了这些,为C++03编译器也提供了std::align
3. 查询对齐
C++11标准库提供了std::alignment_of
的特性来查询对齐所需的类型,但是直到libc++(clang3.4),并没有为数组的类型正确的提供,在msvc14.0中会给数组类型返回错误的值。Boost库实现了这些,为C++03编译器也提供了实现。
4.提示对齐
分配对齐的内存有时不足以确保生成最佳代码。开发人员使用特定的编译器内在函数来通知编译器内存块的给定对齐属性。该库提供了一个宏 , BOOST_ALIGN_ASSUME_ALIGNED
来为具有适当内在函数的编译器抽象该功能。
5. 检查对齐
该库提供了一个函数,is_aligned
用于测试指针值的对齐情况。在断言中验证内存是否正确对齐通常很有用。
三、API
align
包含头文件: boost/align/align.hpp
功能: 对齐一块内存并返回首地址(指针对齐)
接口:
void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space)
输入参数:
- alignment 应当为2的幂,为存储空间对齐的边界值。
- size 为对齐内存的长度
- ptr 为对齐内存后的起始内存地址指针
- space 为对齐内存后的占用大小(长度)
以alignment为对齐边界申请连续size字节的内存,ptr输入时是起始地址,处理完之后是对齐之后的内存空间首地址,space会减少本来偏移的空间字节数(因为ptr不一定正好在以alignment指定的对齐边界上,故需要做偏移)。
实例:
#include <iostream> #include <boost/align/align.hpp> int main(int argc, char** argv) { void* stroge; size_t space = 5000; //按512字节对齐的方式,开辟2000个连续的空间,stroge最初值为0xcccccccccccccccc,本身没有在对齐边界上,需要偏移308个字节地址达到边界,space相应减少308,开辟2000个字节的内存地址,space至少能满足2308的大小。返回的地址就是0xccccccccccccce00,newPtr与stroge的值都是此 void* newPtr = boost::alignment::align(512, 2000, stroge, space); return 0; }
align_up
包含头文件: <boost/align/align_up.hpp>
功能: 返回一个大于等于value的对齐边界(alignment)倍数的值。
接口:
template<class T> constexpr T align_up(T value, std::size_t alignment) noexcept;
输入参数:
- 输入任意值value
- 输入2的幂对齐边界alignment
输出参数:
- 上边界的值
align_down
包含头文件: <boost/align/align_down.hpp>
功能: 返回一个小于等于value的对齐边界(alignment)倍数的值。
接口:
template<class T> constexpr T align_up(T value, std::size_t alignment) noexcept;
输入参数:
- 输入任意值value
- 输入2的幂对齐边界alignment
输出参数:
- 下边界的值
实例:
#include <iostream> #include <boost/align/align.hpp> #include <boost/align/align_up.hpp> #include <boost/align/align_down.hpp> int main(int argc, char** argv) { size_t bound = 567; //输出1024 size_t retUp = boost::alignment::align_up(bound, 512); //输出512 size_t retDown = boost::alignment::align_down(bound, 512); return 0; }
aligned_alloc
包含头文件: <boost/align/aligned_alloc.hpp>
功能: 分配指定对齐方式的连续内存
接口:
void* aligned_alloc(std::size_t alignment, std::size_t size);
输入参数
- 对齐方式alignment(2的幂)
- 连续内存的字节数size
返回
- 开辟的内存的首地址
aligned_free
包含头文件: <boost/align/aligned_alloc.hpp>
功能: 释放对齐内存指针
接口:
void aligned_free(void* ptr);
输入参数
- 开辟的对齐指针ptr
返回
- 空
is_aligned
包含头文件: <boost/align/is_aligned.hpp>
功能: 判断某指针指向的连续空间是否按照指定的对齐方式对齐。
接口:
bool is_aligned(const volatile void* ptr, std::size_t alignment) noexcept; template<class T> constexpr bool is_aligned(T value, std::size_t alignment) noexcept;
输入参数
- 开辟的对齐指针ptr或者指定值,指定的对齐方式
返回
- true or false
实例:
#include <iostream> #include <boost/align/align.hpp> #include <boost/align/aligned_alloc.hpp> #include <boost/align/is_aligned.hpp> int main(int argc, char** argv) { void* storage = boost::alignment::aligned_alloc(32, 1000); if (boost::alignment::is_aligned(storage, 32)) { boost::alignment::aligned_free(storage); } return 0; }
四、相关类
1. aligned_allocator
包含头文件: <boost/align/aligned_allocator.hpp>
构造函数:
aligned_allocator() = default; template<class U> aligned_allocator(const aligned_allocator<U, Alignment>&) noexcept;
成员函数:
pointer allocate(size_type size, const_void_pointer = 0);
返回size * sizeof(T)的存储空的地址首指针,分配不了抛出std::bad_alloc的异常
void deallocate(pointer ptr, size_type);
释放指针ptr引用的空间
size_type max_size() const noexcept;
返回调用allocate()的参数最大值
2. aligned_allocator_adaptor
包含头文件: <boost/align/aligned_allocator_adaptor.hpp>
构造函数:
aligned_allocator_adaptor() = default; //使用Allocator的基类std::forward<A>(alloc)初始化 template<class A> aligned_allocator_adaptor(A&& alloc) noexcept; template<class U> aligned_allocator_adaptor(const aligned_allocator_adaptor<U, Alignment>& other) noexcept;
成员函数:
Allocator& base() noexcept;
返回对象的分配器指针
const Allocator& base() const noexcept;
返回常量对象的分配器指针
pointer allocate(size_type size);
返回一段连续的大小为size * sizeof(value_type)的连续内存空间,对齐方式为指定的最小对齐方式和默认值类型对齐方式的较大者。
pointer allocate(size_type size, const_void_pointer hint);
返回一段连续的大小为size * sizeof(value_type)的连续内存空间,对齐方式为指定的最小对齐方式和默认值类型对齐方式的较大者。hint是通过调用allocate()获得指针。
void deallocate(pointer ptr, size_type size);
通过指针释放空间。
3. aligned_delete
包含头文件: <boost/align/aligned_delete.hpp>
成员运算符:
template<class T> void operator()(T* ptr) noexcept(noexcept(ptr->~T()));
功能: 利用析构函数调用aligned_free()
将参数指针释放。
五、traits
alignment_of
template<class T> struct alignment_of;
包含头文件: <boost/align/alignment_of.hpp>
参考值说明:
T是类模板,需要T作为一个整数常量代表类型的size(std::size_t),T是一个引用数组类型时,要求数组是对齐存储的,而且元素值也是对齐类型的。
六、宏断言
BOOST_ALIGN_ASSUME_ALIGNED
包含头文件: <boost/align/assume_aligned.hpp>
定义:
BOOST_ALIGN_ASSUME_ALIGNED(ptr, alignment)
功能: 断言ptr的内存空间是否按要求对齐
七、官方使用列举
//1.对齐空间分配 //alignment对齐边界 2的幂 //size 字节数 void* storage = boost::alignment::aligned_alloc(alignment, size); //释放空间 boost::alignment::aligned_free(storage); //2.对齐分配器allocator //遵循over-alignment的分配 std::vector<int128_t, boost::alignment::aligned_allocator<int128_t> > vector; //指定动态分配的最小对齐边界的范例 std::vector<double, boost::alignment::aligned_allocator<double, 64> > vector; //3.对齐内存分配器适配器 //将分配器类转换成适配器对象,遵循over-alignment对齐方式 boost::alignment::aligned_allocator_adaptor<First> second(first); //为动态分配指定最小的对齐方式值 boost::alignment::aligned_allocator_adaptor<First, 64> second(first); //4.对齐删除器 //一个删除器应该与aligned_alloc成对使用 std::unique_ptr<double, boost::alignment::aligned_delete> pointer; //5.指针对齐 //算法起始指针,返回对齐后的地址指针 void* pointer = storage; //给定的空间 std::size_t space = size; void* result = boost::alignment::align(64, sizeof(double), pointer, space); //6.查询对齐 //编译期间获知是否根据给定类型对齐 boost::alignment::alignment_of<int128_t>::value //7.宏断言对齐 BOOST_ALIGN_ASSUME_ALIGNED(pointer, 64) //8.条件检查对齐 assert(boost::alignment::is_aligned(pointer, 64));