大型C++;数组导致iOS上出现分段错误 我用C++构建了一个iOS应用程序,遇到了一个大数组的问题。问题是,如果阵列达到一定大小,我会得到EXC_BAD_ACCESS(SIGSEGV)类型的异常,子类型KERN_PROTECTION_FAILURE,带有分段故障(11)终止信号
有趣的是,不管我是将数组放在堆栈上还是堆上,我都会得到这个异常 将数组放入堆栈的代码如下所示:大型C++;数组导致iOS上出现分段错误 我用C++构建了一个iOS应用程序,遇到了一个大数组的问题。问题是,如果阵列达到一定大小,我会得到EXC_BAD_ACCESS(SIGSEGV)类型的异常,子类型KERN_PROTECTION_FAILURE,带有分段故障(11)终止信号,c++,ios,segmentation-fault,clang,C++,Ios,Segmentation Fault,Clang,有趣的是,不管我是将数组放在堆栈上还是堆上,我都会得到这个异常 将数组放入堆栈的代码如下所示: class Model { public: Model() { }; private: static constexpr std::size_t VERTEX_COUNT = 25894; Vertex _vertices[VERTEX_COUNT] = { { { 46.629387f, 647.478271f, 58.987785f }, { 0.140482f,
class Model
{
public:
Model() { };
private:
static constexpr std::size_t VERTEX_COUNT = 25894;
Vertex _vertices[VERTEX_COUNT] =
{
{ { 46.629387f, 647.478271f, 58.987785f }, { 0.140482f, 0.716024f, 0.683795f }, false },
{ { 86.409439f, 639.203247f, 57.095085f }, { 0.273239f, 0.689217f, 0.671059f }, false },
{ { 94.825722f, 586.618164f, 91.772812f }, { 0.375726f, 0.404750f, 0.833671f }, false },
{ { 50.570183f, 586.068481f, 100.536209f }, { -0.003906f, 0.451161f, 0.892434f }, false },
// 25894 array entries in total
};
// all the rest
}
struct Vertex
{
Vertex()
{
}
Vertex(glm::vec3 coords, glm::vec3 norm, bool selected) :
coordinates(coords),
normal(norm),
isSelected(selected)
{
}
glm::vec3 coordinates;
glm::vec3 normal;
bool isSelected;
};
用于填充数组的结构如下所示:
class Model
{
public:
Model() { };
private:
static constexpr std::size_t VERTEX_COUNT = 25894;
Vertex _vertices[VERTEX_COUNT] =
{
{ { 46.629387f, 647.478271f, 58.987785f }, { 0.140482f, 0.716024f, 0.683795f }, false },
{ { 86.409439f, 639.203247f, 57.095085f }, { 0.273239f, 0.689217f, 0.671059f }, false },
{ { 94.825722f, 586.618164f, 91.772812f }, { 0.375726f, 0.404750f, 0.833671f }, false },
{ { 50.570183f, 586.068481f, 100.536209f }, { -0.003906f, 0.451161f, 0.892434f }, false },
// 25894 array entries in total
};
// all the rest
}
struct Vertex
{
Vertex()
{
}
Vertex(glm::vec3 coords, glm::vec3 norm, bool selected) :
coordinates(coords),
normal(norm),
isSelected(selected)
{
}
glm::vec3 coordinates;
glm::vec3 normal;
bool isSelected;
};
一旦模型的实例被实例化,上述代码就会在iOS 11.4上崩溃
现在,即使我改变路线,这种情况也会发生
Vertex _vertices[VERTEX_COUNT] =
到(在堆上分配内存)
或
到
并将相应的constexpr构造函数添加到顶点
结构中。但是,我需要能够在运行时编辑数组,因此不能将其声明为static constexpr
有人知道这里可能发生了什么吗?您应该通过
new
创建数组,而不必初始化其元素。当您通过初始化在堆上创建数组时,编译器需要在堆栈上准备足够的空间,以便为数组的多个对象调用CTOR
请看下面的示例(它说明了通过初始化创建动态数组是危险的):
现在编译器生成子rsp,80,正如您可以看到的,从堆栈指针减去的值增加了
顶点数组越大,从堆栈中获得的空间就越多。堆栈是有限的。这可能就是为什么即使将数组分配到堆上,应用程序也会崩溃。堆栈的所有内存都用于初始化数组的顶点
我在上编译了这段代码,选择了Clang6.0,没有进行任何优化。(已启用的优化在输出asm代码中发生了很大变化)。当然,其他编译器可能会生成不同的代码,而不是
sub-rsp,BIG_VALUE
,它们可以分别为顶点的每个向量部分占用堆栈空间 在嵌入式系统中,经验法则是将常量和大量数据声明为静态
:
static Vertex database[] = {/*...*/};
如果数据是只读的,请使用const
关键字:
static const Vertex database[] = {/*...*/};
检查编译器和链接器文档,查看是否可以为数据创建内存段,以及如何将数据库分配给该内存段
您的编译器可能会对上述技术施加限制,例如必须只使用struct
,或者Vertex
不能有任何虚拟方法。最糟糕的情况是,您必须使用2d阵列:
static const double Vertices[MAXIMUM_ROWS][3] = {/*...*/};
通过使用
静态常量
,编译器可以将数据放入只读数据段。这允许将数据放入只读存储器设备,如闪存或ROM(是的,我知道闪存可以写入/编程,但大多数情况下,它被视为ROM)。听起来像是在创建多个型号的实例,因此很快就会耗尽内存。静态
\u顶点
成员将其设置为只有1个大数组而不是NDO。如果移除constexpr
并在类外初始化它,它不工作吗?@AndyG:即使我只创建了模型
的单个实例,我也遇到了问题。这个实例一创建,问题就来了。@TedLyngmo:你的意思是让数组只是静态的吗?是的,我就是这么想的。该数组有多大(以字节为单位)?621456-828608字节什么的?你能做新字符[828608]代码>或`字符a[828608];没有问题吗?这对我来说很有意义,并且可以解释为什么我为堆栈上的数组还是堆分配内存实际上并不重要。但我仍然无法理解如何在初始化数组时防止堆栈被顶点结构弄乱。按如下方式修改代码似乎仍然具有相同的效果:顶点*v=新顶点[6];v[0]=顶点(1.43,2,3);v[1]=顶点(3,4.34,5);v[2]=顶点(3,4,5)。。。您对如何更改代码以防止该问题有何意见?对我来说,最简单的方法是将所有double和bool移动到数据段中,因此您定义了两个全局数组double valD[]={1,2,3};布尔值[]={true,false,true}代码>。编译器将两个数组的所有数据放入数据段-这是安全的。然后通过new
在堆上分配数组,并在一个for循环中为顶点调用ctor,为(int i=0;i<25K;++i){a[i]=Vertex(valD[i],valD[i+1],…valB[i])}
的数组的所有元素提供参数。
vertex* v = new vertex[6] {
{1.43,2,3},
// 4 lines here
{3,4,5}
static Vertex database[] = {/*...*/};
static const Vertex database[] = {/*...*/};
static const double Vertices[MAXIMUM_ROWS][3] = {/*...*/};