【问题标题】:String array not deallocated upon scope exit范围退出时未释放字符串数组
【发布时间】:2012-01-15 22:41:19
【问题描述】:

我在我的应用程序中遇到了一些严重的内存泄漏,所以我设置了这个非常简单的解决方案来测试当字符串数组超出范围时会发生什么......

我知道 String 的旧 TextString 实现缺少析构函数,但当前的实现似乎有它。

我正在使用this MemoryFree library请注意,此链接代码现已根据该问题的公认答案修复)。

代码检查了两种情况:在两个不同的函数中分配 char 数组和 string 数组以强制两者都退出范围。

#include <MemoryFree.h>

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  int freeBefore, freeAfter;

  //TEST ALLOCATION OF CHAR ARRAY//
  freeBefore = freeMemory();
  AllocateCharArr();
  freeAfter = freeMemory();
  Serial.println("CHAR*: Before " + String(freeBefore)
    + ", After " + String(freeAfter)
    + ", Diff " + String(freeBefore - freeAfter));

  //TEST ALLOCATION OF STRING//
  freeBefore = freeMemory();
  AllocateStringArr();
  freeAfter = freeMemory();
  Serial.println("STRING: Before " + String(freeBefore)
    + ", After " + String(freeAfter)
    + ", Diff " + String(freeBefore - freeAfter));
}

void AllocateCharArr() {
  char s[100];
}

void AllocateStringArr() {
  String s[100];
}

void loop() { /* empty */ }

输出:

CHAR*:1710 之前,1710 之后,差异 0
字符串:1645 之前,1309 之后,差异 336

String 数组分配怎么没有从内存中擦除?

【问题讨论】:

  • String 数组更小(例如,10 个元素)时的结果是什么?
  • 有趣:50 个元素=diff 136, 25 个元素=diff 36, 10 个元素=diff 0
  • 您使用的是什么版本的 Arduino 软件(0023、1.0、...)?
  • 我使用的是 1.0 版软件,在带有 ATmega328 控制器的 Arduino UNO R3 板上运行。

标签: c arduino


【解决方案1】:

在测试String 类 (see forum post here) 时,我在 1.0 之前的 Arduino 版本中遇到了内存处理问题。

String 构造函数在内部使用realloc,正是这个(avr libc)动态内存处理导致了问题(由于指向堆顶部的指针__brkval 没有在free() 上更新)。

运行以下代码以查看版本 0023、0022 等中的这些问题。在 Arduino 1.0 中,代码应显示没有内存泄漏:

#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include <HardwareSerial.h>
#include <MemoryFree.h>

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  int freeBefore, freeAfter;

  freeBefore = freeMemory();

  void* buffer = malloc(10);
  if (buffer == 0) {
    Serial.println("Failed to allocate memory");
  }
  free(buffer);

  freeAfter = freeMemory();
  Serial.println("Before " + String(freeBefore)
    + ", After " + String(freeAfter)
    + ", Diff " + String(freeBefore - freeAfter));
}

void loop() {
}

此外,您使用的 MemoryFree 库可能会给出错误的结果,因为它没有考虑空闲列表。试试这个更新版本的MemoryFree.cpp

extern unsigned int __heap_start;
extern void *__brkval;

/*
 * The free list structure as maintained by the 
 * avr-libc memory allocation routines.
 */
struct __freelist {
  size_t sz;
  struct __freelist *nx;
};

/* The head of the free list structure */
extern struct __freelist *__flp;

#include "MemoryFree.h";

/* Calculates the size of the free list */
int freeListSize() {
  struct __freelist* current;
  int total = 0;

  for (current = __flp; current; current = current->nx) {
    total += 2; /* Add two bytes for the memory block's header  */
    total += (int) current->sz;
  }

  return total;
}

int freeMemory() {
  int free_memory;

  if ((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__heap_start);
  } else {
    free_memory = ((int)&free_memory) - ((int)__brkval);
    free_memory += freeListSize();
  }
  return free_memory;
}

【讨论】:

  • 谢谢!原来是 freeMemory 函数报告了错误的值。改用您提供的方法,可以得到正确的结果,并且似乎不会发生泄漏。
  • 很高兴知道 Arduino 1.0 库没问题。将更新答案。谢谢!
  • 我已经根据这个公认的答案更新了 Arduino 网站 (arduino.cc/playground/Code/AvailableMemory) 上的 MemoryFree.cpp 库代码。
【解决方案2】:

如果您查看Arduino source,您可能会遇到文件“.\arduino-1.0\hardware\arduino\cores\arduino\WString.cpp”。在这个文件中,我注意到 String 没有默认(无参数)构造函数。也许这可能是问题所在?值得怀疑,但无论如何,来源应该有所帮助。祝你好运。

【讨论】:

  • 我已经在查看该文件,主要是为了验证它是否具有析构函数。我将测试以值初始化的数组是否有任何区别。
【解决方案3】:

注释掉String s[100];这一行,看看你是否得到不同的结果。看起来您看到的内存分配是由于 setup() 函数中的字符串操作,而不是 AllocateStrArr() 中声明的本地字符串数组。您可以查看WString.cppWString.h 以了解operator+ 已被覆盖,因此每次调用String() 或使用+ 进行连接都可以创建另一个对象。

【讨论】:

  • 评论该行使其差异为 0。
猜你喜欢
  • 2020-11-10
  • 2010-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-23
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多