内存未被释放,导致巨大的内存泄漏

时间:2010-05-02 11:01:39

标签: c++ memory memory-leaks

不幸的是,解决方案还没有奏效;将result.values指针设置为0实际上并没有减少内存使用量。我也尝试过free(result.values)代替那个,但这不是必需的,因为它会删除我的字符串。

编辑2:我会尝试编写一个堆栈析构函数。

编辑3:陷入困境。感谢DeadMG,编写一个免费(值)完美伎俩的析构函数!哇......太简单了。

在我的C ++ Unicode库中,ustring类为char *值和其他ustring值设置了operator = functions。在进行简单的内存泄漏测试时:

#include <cstdio>
#include "ucpp"
main() {
  ustring a;
  for(;;)a="MEMORY";
}

程序使用的内存不受控制地增长(具有大内存泄漏的程序的特征),即使我已经为这两个函数添加了free()调用。我不确定为什么这是无效的(我在其他地方错过了free()调用吗?)

这是当前的库代码:

#include <cstdlib>
#include <cstring>
class ustring {
  int * values;
  long len;
  public:
  long length() {
    return len;
  }
  ustring() {
    len = 0;
    values = (int *) malloc(0);
  }
  ustring(const ustring &input) {
    len = input.len;
    values = (int *) malloc(sizeof(int) * len);
    for (long i = 0; i < len; i++)
      values[i] = input.values[i];
  }
  ustring operator=(ustring input) {
    ustring result(input);
    free(values);
    len = input.len;
    values = input.values;
    return * this;
  }
  ustring(const char * input) {
    values = (int *) malloc(0);
    long s = 0;                                                                 // s = number of parsed chars
    int a, b, c, d, contNeed = 0, cont = 0;
    for (long i = 0; input[i]; i++)
      if (input[i] < 0x80) {                                                    // ASCII, direct copy (00-7f)
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = input[i];
      } else if (input[i] < 0xc0) {                                             // this is a continuation (80-bf)
        if (cont == contNeed) {                                                 // no need for continuation, use U+fffd
          values = (int *) realloc(values, sizeof(int) * ++s);
          values[s - 1] = 0xfffd;
        }
        cont = cont + 1;
        values[s - 1] = values[s - 1] | ((input[i] & 0x3f) << ((contNeed - cont) * 6));
        if (cont == contNeed) cont = contNeed = 0;
      } else if (input[i] < 0xc2) {                                             // invalid byte, use U+fffd (c0-c1)
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = 0xfffd;
      } else if (input[i] < 0xe0) {                                             // start of 2-byte sequence (c2-df)
        contNeed = 1;
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = (input[i] & 0x1f) << 6;
      } else if (input[i] < 0xf0) {                                             // start of 3-byte sequence (e0-ef)
        contNeed = 2;
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = (input[i] & 0x0f) << 12;
      } else if (input[i] < 0xf5) {                                             // start of 4-byte sequence (f0-f4)
        contNeed = 3;
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = (input[i] & 0x07) << 18;
      } else {                                                                  // restricted or invalid (f5-ff)
        values = (int *) realloc(values, sizeof(int) * ++s);
        values[s - 1] = 0xfffd;
      }
    len = s;
  }
  ustring operator=(const char * input) {
    ustring result(input);
    free(values);
    len = result.len;
    values = result.values;
    return * this;
  }
  ustring operator+(ustring input) {
    ustring result;
    result.len = len + input.len;
    result.values = (int *) malloc(sizeof(int) * result.len);
    for (long i = 0; i < len; i++)
      result.values[i] = values[i];
    for (long i = 0; i < input.len; i++)
      result.values[i + len] = input.values[i];
    return result;
  }
  ustring operator[](long index) {
    ustring result;
    result.len = 1;
    result.values = (int *) malloc(sizeof(int));
    result.values[0] = values[index];
    return result;
  }
  operator char * () {
    return this -> encode();
  }
  char * encode() {
    char * r = (char *) malloc(0);
    long s = 0;
    for (long i = 0; i < len; i++) {
      if (values[i] < 0x80)
        r = (char *) realloc(r, s + 1),
        r[s + 0] = char(values[i]),
        s += 1;
      else if (values[i] < 0x800)
        r = (char *) realloc(r, s + 2),
        r[s + 0] = char(values[i] >> 6 | 0x60),
        r[s + 1] = char(values[i] & 0x3f | 0x80),
        s += 2;
      else if (values[i] < 0x10000)
        r = (char *) realloc(r, s + 3),
        r[s + 0] = char(values[i] >> 12 | 0xe0),
        r[s + 1] = char(values[i] >> 6 & 0x3f | 0x80),
        r[s + 2] = char(values[i] & 0x3f | 0x80),
        s += 3;
      else
        r = (char *) realloc(r, s + 4),
        r[s + 0] = char(values[i] >> 18 | 0xf0),
        r[s + 1] = char(values[i] >> 12 & 0x3f | 0x80),
        r[s + 2] = char(values[i] >> 6 & 0x3f | 0x80),
        r[s + 3] = char(values[i] & 0x3f | 0x80),
        s += 4;
    }
    return r;
  }
};

5 个答案:

答案 0 :(得分:13)

ustring的析构函数在哪里?它不应该释放分配的内存吗?


让我们看看,例如在任务操作员处:

ustring operator=(ustring input)
{
    ustring result(input);
    ...
    return *this;
}

您按值传递ustring参数。这可能会导致通过复制构造函数创建副本。您再次调用复制构造来初始化result。我怀疑你在*this作为ustring返回时再次调用复制构造(再次按值而不是通过引用)。

让我们看看这三种情况中的一种,即result:当这个局部变量超出范围时(即在函数末尾),它将被自动销毁。但是如果你没有提供~ustring分配内存的析构函数(free),你就会出现内存泄漏。

由于你显然已经大量的拷贝构造和传递值而没有析构函数来释放分配的内存,你将获得大量的很多不同的内存。


此外:为什么使用mallocfree代替new[]delete[]你可以摆脱丑陋的{{ 1}}计算和sizeof(int) * ...类型转换。而不是:

(int*)
你只需写下:

values = (int *) malloc(sizeof(int) * len);

答案 1 :(得分:4)

基本上,你创建了太多的ustrings,你需要更多的引用,并且你没有实现析构函数,因此当它们全部从堆栈中掉落时,它们就不会被释放。

此外,在赋值运算符中,需要将result.values设置为NULL,否则将删除内存。您可以使用移动运算符来使其快速运行,但我仍然不明白为什么会这样做。

答案 2 :(得分:2)

  ustring operator=(ustring input) {
    ustring result(input);
    free(values);
    len = input.len;
    values = input.values;
    return * this;
  }

为什么要在此声明result

答案 3 :(得分:2)

一旦你实现了析构函数,这个赋值实现就会咬你

  ustring operator=(const char * input) {
    ustring result(input);
    free(values);
    len = result.len;
    values = result.values;
    return * this;
  }

不,这不是让析构函数没有实现的论据。

修改

ustring对象拥有一个用malloc分配的数组,当它被销毁时应释放该内存。

如果您创建本地对象

    ustring result(input);

当函数返回时它将被销毁。

在第

    values = result.values;

你从你的本地对象 - 结果复制指针,但结果不知道它,所以它应该销毁数组并留下*这个悬挂指针。您必须以某种方式更改结果的状态,以防止它释放内存,因为您从中获取了数组的所有权。一种方法是将它的指针设置为null。在空指针上调用free是合法的,因此您不必担心尝试通过结果的析构函数释放内存。

ustring& operator=(const char * input) {
    ustring result(input);
    free(values);
    len = result.len;
    values = result.values;
    result.values = 0;
    return * this;
}

答案 4 :(得分:0)

  1. 尝试使用RAII-techniques以避免内存泄漏问题。如果将数组包装在类似boost::shared_array之类的内容中,则不必编写显式析构函数来释放内存。
  2. ustring operator=(ustring input)应为ustring operator=(const ustring & input),以避免副本的副本。如果将非整数类型作为只读参数传递,则应始终执行此操作。
  3. 使用shared_array之类的东西也可以摆脱计算大小的问题。
  4. 只是一些提示。另一方面,您的代码难以阅读和理解。如果你希望其他人能够使用它,你应该真的做些什么。使您的名称更具描述性,将重复出现的代码重构为表达其功能的函数。例如,您可以使用std::copy而不是使用for - 循环来复制您的值。您也可以考虑用名称表示值语义的常量替换所有幻数(例如0x1f)。