字节对齐:
计算机存储系统中以Byte为单位存储数据,不同数据类型所占的空间不同,如:整型(int)数据占4个字节,字符型(char)数据占一个字节,短整型(short)数据占两个字节,等等。计算机为了快速的读写数据,默认情况下将数据存放在某个地址的起始位置,如:整型数据(int)默认存储在地址能被4整除的起始位置,字符型数据(char)可以存放在任何地址位置(被1整除),短整型(short)数据存储在地址能被2整除的起始位置。这就是默认字节对齐方式。
对于32位地址空间,由于是按Byte寻址的,而不是按bit位寻址的,本来所有的bit的地址空间是2^32, 现在俺Byte寻址的话,地址空间就是2^24了,所以,一个变量的地址的最高8个bit总是0。参考后续试验[1]
1)提高存取效率 一般处理器是32位的,一次可以从内存中读取32位数据,一般分配给变量地址是4的倍数,如果你定义的结构成员横跨了32位边界,CPU要读取2次。这里就是浪费了时间。 2)为了在不同处理器下兼容。 早期MIPS处理器只能读取4字节对齐的后的结构,非4倍数地址访问,会造成死机问题。 3)VC一般默认8字节对齐是为了配合64位处理器,8也是4的倍数,因此也适合32位处理器。但就是浪费内存。 4)内存紧张的嵌入式环境,常会需要1字节对齐 。。 |
对齐的函数
//实现了指针对齐的直观的函数
void* myAlignPtr( const void* ptr, int align=32 )
{
int ret = 0;
int remainder = (size_t)ptr % align;
if ( 0 == remainder )
{
ret = (size_t)ptr;
}
else
{
ret = (size_t)ptr - remainder + align;
}
return (void*)ret;
}
在opencv里,该函数被简化成为了
void* cvAlignPtr( const void* ptr, int align=4 )
{
assert( (align & (align-1)) == 0 ); // 确保align是2的整数幂
return (void*)( ((size_t)ptr + align - 1) & ~(size_t)(align-1) ); // 求ptr-ptr%align
}
// opencv的该函数里面,align的值默认为32,也就是,通过malloc申请的内存,多申请了32个字节,以便可以支持32字节对齐。
下面是 我打印出来的一些连续定义的整形变量地址的值:
0x0012FF68
0x0012FF6C
0x0012FF70
0x0012FF74
0x0012FF78
0x0012FF7C
以10进制输出:
可以看出,1)高位的8个比特位为0 2)相邻的地址差为4,也就是说,一个整形变量占空间为4个byte。
1: opencv库大多数接口都是以c函数提供的。 哎,c最大的麻烦就是内存管理。想想stl的vector,map等用着多舒服。。。 不过话说回来,opencv为了尽可能的通用,用c更好。 那么这里就总结些opencv的常见的内存问题: