• [工作积累] GCC 4.6 new[] operator内存对齐的BUG


    对于用户没有定义dctor(包括其所有成员)的类来说, new CLASS[n] 可能会直接请求sizeof(CLASS)*n的空间.

    而带有dctor的 类, 因为delete[]的时候要逐个调用析构函数, 要保证调用n次析构.

    C++标准没有指定如何具体处理这种情况. 而对于很多数编译器来说, 是在请求的内存前面, 保存对象的个数n(放在其头部).

    sizeof(int)  sizeof(CLASS)  ...      
    n Object[0] Object[1] Object[2] ... Object[n-1]

    on new[]:

    1.call CLASS::operator new[], or ::operator new[] ( n*sizeof(CLASS) + sizeof(int) ) to allocate memory

    2.write number n to first memory address

    3.offset base in sizeof(int), to locate array base(beginning)

    4.call ctor for all objects

    on delete[] (ptr)

    1.real base: offset ptr in -sizeof(int)

    2.read the array element count 'n' in real memory base

    3.for each object in array ptr, call dctor for 'n' times

    4.call CLASS::operator delete[] , or ::operator delete[] (real base) to free memory

    基本原理就是上面这样. 对于处理algined的数据, 编译器需要做额外处理:

    1. 要求CLASS::operator new[] 分配出的内存已经是对齐的, 编译器假定它分配的是对齐的内存, 也就是说, 用户实现的CLASS::operator new[] , 需要使用对齐分配.

    1 struct __declspec(align(16)) Test
    2 {
    3     ...
    4     void* operator new[](size_t bytes)
    5     {
    6          return _aligned_malloc(bytes, 16);
    7     }
    8 };

    2.sizeof(CLASS) 是对齐后的值, 否则无法保证array中后续所有元素都是对齐的.

    3.在上面的基础上, 编译器请求的内存大小有轻微区别:

    请求的内存数量稍微偏多:n*sizeof(CLASS) + sizeof(int) =>  n* sizeof(CLASS) + aligned( sizeof(int) )

    注意上面, 前后的 sizeof(CLASS) 的值是不一样的, 前者没有对齐, 后者是对齐后的, 也就是说加了alignment以后, sizeof()的值不一样.

    4.偏移量也需要对齐, 从而保证偏移以后的base address是对齐的: 即offset不再是sizeof(int), 而是aligned(sizeof(int))

    这样可以保证最终使用的数组是对齐的.

    aligned( sizeof(int) )  sizeof(CLASS) : aligned  ...      
    n Object[0] Object[1] Object[2] ... Object[n-1]

     

     

     

    上面的除了operator new[] 需要用户实现以外, 编译器都会把剩余的工作做完.

    经过测试MSVC11和MinGW GCC 4.8 都是没有问题的.

    但是在android的GCC4.6上是有bug的, offset忽略了对齐的问题, 使用了固定偏移量8. 解决方y法是hack, 在operator new[]/delete[]里面手动处理offest.

  • 相关阅读:
    数学形态学——腐蚀、膨胀、开、闭、细化
    VS2010中 报错:error C2146、error C4430 原因一:缺少CvvImage类
    帧同步和状态同步
    HTML5触摸事件演化tap事件
    screenX clientX pageX的区别
    phaser的小游戏的onInputDown问题
    phaser入手
    pixi.js 微信小游戏 入手
    正则表达式
    剖析Vue原理&实现双向绑定MVVM-2
  • 原文地址:https://www.cnblogs.com/crazii/p/4218670.html
Copyright © 2020-2023  润新知