2

我正在进行的一个项目涉及一个飞行器,其 GNC 代码用 C 库 (.out) 编写。我们必须以 .out 库的形式从 LabVIEW(主要的航空电子软件)调用此 C 代码,并且该软件的性质需要静态指针来存储对函数的连续调用之间的数据。我们在整个飞行过程中定期调用 GNC 执行功能。我现在尝试在 Windows 上的 DLL 中使用 Matlab MEX 包装器调用此函数,这发现了一些内存管理问题。

我在函数的开头声明结构,如下所示:

static Nav_str *Nav_IN_OUT_ptr;
static  hguid_ref *Guid_IN_OUT_ptr;
static  HopControl *Control_IN_OUT_ptr;

Nav_IN_OUT_ptr = (Nav_str *)malloc(sizeof(Nav_str));
Guid_IN_OUT_ptr = (hguid_ref *)malloc(sizeof(hguid_ref));
Control_IN_OUT_ptr = (HopControl *)malloc(sizeof(HopControl));

这发生在函数的每次运行期间。但是,在多次迭代调用此函数后,它总是在尝试退出后崩溃并出现内存分段错误。我的理解是这个内存应该自己清理,这是不正确的吗?

为了手动清理它,我将这些行添加到最后,仅在清理迭代时调用:

free(Nav_IN_OUT_ptr);
free(Guid_IN_OUT_ptr);
free(Control_IN_OUT_ptr);

这是释放此内存的正确方法吗?我可以释放这段记忆吗?除了 C 在最后一次调用后没有正确放弃内存或 Matlab 没有正确管理其内存之外,分段错误是否还有其他原因?我已经到处寻找有类似问题的人(甚至联系 Mathworks),但运气不佳,因此非常感谢任何意见或建议。

4

3 回答 3

3

未能释放内存不会导致分段错误。您的问题很可能出在其他地方。两种可能的情况是:

  1. 溢出缓冲区
  2. 使用指向先前已释放的内存的指针。
  3. 使用错误的指针值,不知何故设置不正确。
  4. 试图释放 malloc'd(或已释放)未返回的指针

我的理解是这个内存应该自己清理,这是不正确的吗?

是的,您需要调用free()以将内存释放回堆。我还建议您将指针值设置为nullfree 之后,这可以帮助您从上面捕获条件 2。


Nav_IN_OUT_ptr = (Nav_str *)malloc(sizeof(Nav_str));

这个代码声明是有问题的。什么是Nav_str类型?你确定你不是要使用strlen(Nav_str)+1吗?


我还需要问一下使您的指针静态化的目的是什么?静态函数变量基本上是全局变量,仅在极少数情况下使用。

于 2011-04-19T00:54:47.633 回答
2

您的代码确实存在内存泄漏 - 每次调用函数时都会分配该内存。即使您当前的方法仍然存在内存泄漏 - 如果您free()在最后一次迭代中只调用一次,那么您只释放了最近的分配。

但是,内存泄漏通常不会导致分段错误(除非您的内存泄漏耗尽了所有可用内存,导致后续malloc()调用 return NULL)。

如果您希望拥有只分配一次并重复使用的静态结构,则根本不需要使用malloc()- 您只需将声明更改为:

static Nav_str Nav_IN_OUT;
static hguid_ref Guid_IN_OUT;
static HopControl Control_IN_OUT;

... 并使用Nav_IN_OUT.field代替Nav_IN_OUT_ptr->field, 和&Nav_IN_OUT代替Nav_IN_OUT_ptr(如果您直接将指针值传递给其他函数)。

于 2011-04-19T00:57:57.507 回答
1

我的理解是这个内存应该自己清理,这是不正确的吗?

对不起,你错了。:) 分配的内存malloc()将持续存在,直到您使用free(). (最后你确实做对了。万岁。:)

这是释放此内存的正确方法吗?我可以释放这段记忆吗?

释放内存的正确方法,但它可能不在正确的位置。一般来说,试着在写free()电话的同时写malloc()电话。

也许您在函数开始时分配,然后在函数结束时释放。(在这种情况下,如果内存仅由原始函数调用的函数使用,则堆栈内存使用可能会更好。)

也许您有一个从 APIfoo_init()调用malloc()和创建关联上下文的函数,然后您将该上下文传递给对该数据进行操作的其他例程,然后您需要将free()调用放入一个foo_destroy()foo_free()类似的例程中。然后,您的所有呼叫者都需要平衡foo_init()foo_free()呼叫。如果您不能只在一个函数中编写foo_init()andfoo_destroy()调用,这将特别合适;比如说,您的对象可能需要在更大的事件循环中的某个随机点被删除。

也许数据应该只分配一次并且永远存在。这对于某些应用程序设计来说是正确的,并且很难仅从变量名中判断这些数据块是否应该永远存在。

除了 C 在最后一次调用后没有正确放弃内存或 Matlab 没有正确管理其内存之外,分段错误是否还有其他原因?

肯定有;也许这个内存被返回得太快了,也许某个指针被free()编辑了两次或更多次,或者你正在覆盖你的缓冲区(这个malloc(sizeof(Nav_str))调用有点令人担忧;它可能只是根据指针大小分配四个八个字节在您的平台上;并且在将其替换为 之前strlen(),请注意strlen()不会NUL在字符串末尾为字节留出空间;malloc(len+1);是为字符串分配内存的常用模式,每当我不到时我都会担心在+1通话中。)

使用一段时间valgrind无疑会帮助发现内存错误,也许使用 Electric Fence 一段时间会有所帮助。valgrind绝对更新,并且绝对可以更好地处理“大型”程序(因为电子围栏会为每个 分配一个新页面malloc(),它可能很昂贵)。

于 2011-04-19T01:02:57.147 回答