在分配有 new[] 的数组上使用 avx 时出现分段错误(核心已转储)
Segmentation fault (core dumped) when using avx on an array allocated with new[]
当我在 visual studio 2015 年 运行 此代码时,该代码有效 correctly.But 该代码在代码块中生成以下错误:分段错误(核心已转储)。我也 运行 ubuntu 中的代码有同样的错误。
#include <iostream>
#include <immintrin.h>
struct INFO
{
unsigned int id = 0;
__m256i temp[8];
};
int main()
{
std::cout<<"Start AVX..."<<std::endl;
int _size = 100;
INFO *info = new INFO[_size];
for (int i = 0; i<_size; i++)
{
for (int k = 0; k < 8; k++)
{
info[i].temp[k] = _mm256_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);
}
}
std::cout<<"End AVX."<<std::endl;
return 0;
}
问题是在 C++17 之前 new
和 delete
不遵守待分配类型的对齐方式。如果您查看从这个简单函数生成的程序集:
INFO* new_test() {
int _size = 100;
INFO *info = new INFO[_size];
return info;
}
你会看到,当用 C++17 之前的任何东西编译时,都会调用 operator new[](unsigned long)
,而对于 C++17,会调用 operator new[](unsigned long, std::align_val_t)
(和 32
为第二个参数传递)。
Play around with it at godbolt.
如果你不能使用 C++17,你可以覆盖 operator new[]
(和 operator delete[]
——你也应该覆盖 operator new
和 operator delete
...):
struct INFO {
unsigned int id = 0;
__m256i temp[8];
void* operator new[](size_t size) {
// part of C11:
return aligned_alloc(alignof(INFO), size);
}
void operator delete[](void* addr) {
free(addr); // aligned_alloc is compatible with free
}
};
如果你用 -DOVERWRITE_OPERATOR_NEW
编译的话,这是前面 godbolt 例子的一部分。
请注意,这并不能解决使用 std::vector
(或任何其他 std
-容器时的对齐问题,因为您需要将对齐的分配器传递给容器(不是前面的例子)。
我找到了两种方法来解决这个问题
The first solution
struct INFO
{
__m256i temp[8];
unsigned int id = 0;
};
INFO *info = static_cast<INFO*>(_mm_malloc(sizeof(INFO)*_size, 32));
_mm_free(info);
The second solution
INFO *info = new INFO[_size];
for (int i = 0; i < _size; i++)
{
INFO new_info;
for (int k = 0; k < 8; k++)
{
new_info.temp[k] = _mm256_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);
}
info[i] = new_info;
}
当我在 visual studio 2015 年 运行 此代码时,该代码有效 correctly.But 该代码在代码块中生成以下错误:分段错误(核心已转储)。我也 运行 ubuntu 中的代码有同样的错误。
#include <iostream>
#include <immintrin.h>
struct INFO
{
unsigned int id = 0;
__m256i temp[8];
};
int main()
{
std::cout<<"Start AVX..."<<std::endl;
int _size = 100;
INFO *info = new INFO[_size];
for (int i = 0; i<_size; i++)
{
for (int k = 0; k < 8; k++)
{
info[i].temp[k] = _mm256_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);
}
}
std::cout<<"End AVX."<<std::endl;
return 0;
}
问题是在 C++17 之前 new
和 delete
不遵守待分配类型的对齐方式。如果您查看从这个简单函数生成的程序集:
INFO* new_test() {
int _size = 100;
INFO *info = new INFO[_size];
return info;
}
你会看到,当用 C++17 之前的任何东西编译时,都会调用 operator new[](unsigned long)
,而对于 C++17,会调用 operator new[](unsigned long, std::align_val_t)
(和 32
为第二个参数传递)。
Play around with it at godbolt.
如果你不能使用 C++17,你可以覆盖 operator new[]
(和 operator delete[]
——你也应该覆盖 operator new
和 operator delete
...):
struct INFO {
unsigned int id = 0;
__m256i temp[8];
void* operator new[](size_t size) {
// part of C11:
return aligned_alloc(alignof(INFO), size);
}
void operator delete[](void* addr) {
free(addr); // aligned_alloc is compatible with free
}
};
如果你用 -DOVERWRITE_OPERATOR_NEW
编译的话,这是前面 godbolt 例子的一部分。
请注意,这并不能解决使用 std::vector
(或任何其他 std
-容器时的对齐问题,因为您需要将对齐的分配器传递给容器(不是前面的例子)。
我找到了两种方法来解决这个问题
The first solution
struct INFO
{
__m256i temp[8];
unsigned int id = 0;
};
INFO *info = static_cast<INFO*>(_mm_malloc(sizeof(INFO)*_size, 32));
_mm_free(info);
The second solution
INFO *info = new INFO[_size];
for (int i = 0; i < _size; i++)
{
INFO new_info;
for (int k = 0; k < 8; k++)
{
new_info.temp[k] = _mm256_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);
}
info[i] = new_info;
}