代码之家  ›  专栏  ›  技术社区  ›  Delan Azabani

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

  •  1
  • Delan Azabani  · 技术社区  · 15 年前

    不幸的是,解决方案还没有起作用;将result.values指针设置为0实际上并不能减少内存使用量。我也尝试了用free(result.values)来代替它,但这并不是期望的,因为它会删除我的字符串。

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

    编辑3:明白。感谢Deadmg,编写一个析构函数,让free(values)完美地完成了这个技巧!真的。。。这么简单。

    在C++的Unicode库中,Outlook类具有用于char *值和其他美化值的运算符=函数。执行简单内存泄漏测试时:

    #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 回复  |  直到 15 年前
        1
  •  4
  •   Puppy    15 年前

    基本上,您创建了太多的UString,需要更多的引用,并且没有实现析构函数,所以当它们都从堆栈中脱落时,它们就不会被释放。

    另外,在赋值运算符中,需要将result.values设置为空,否则内存将被删除。你可以用一个移动接线员使这是一个很好的快速操作,虽然我仍然不明白为什么你会这样做。

        2
  •  13
  •   stakx - no longer contributing Saravana Kumar    15 年前

    毁灭者在哪里 属于 ustring ?它不应该释放分配的内存吗?


    例如,让我们看一下赋值运算符:

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

    你通过了 护城河 按值列出的参数。这可能会导致通过复制构造函数创建一个副本。另一次调用复制构造以初始化 result . 我怀疑你在另一次返回时调用了复制构造。 *this 作为一个 护城河 (再次按值,而不是参照)。

    让我们看看这三个案例中的一个,即 结果 :当此局部变量超出范围(即在函数末尾)时,它将自动销毁。但是如果你不提供一个析构函数( ~ustring ) free 是分配的内存,会导致内存泄漏。

    既然你显然 大量的复制构造和传递值在没有析构函数的情况下进行 为了释放分配的内存,您将获得大量未释放的内存。


    另外:你为什么要用 malloc 自由的 而不是 new[] delete[] ? 你可以摆脱丑陋 sizeof(int) * ... 计算和 (int*) 类型转换。而不是:

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

    你只需写:

    values = new int[len];
    
        3
  •  2
  •   Amber    15 年前
      ustring operator=(ustring input) {
        ustring result(input);
        free(values);
        len = input.len;
        values = input.values;
        return * this;
      }
    

    为什么是 result 在这里被宣布?

        4
  •  2
  •   Maciej Hehl    15 年前

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

      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;
    

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

    ustring& operator=(const char * input) {
        ustring result(input);
        free(values);
        len = result.len;
        values = result.values;
        result.values = 0;
        return * this;
    }
    
        5
  •  0
  •   Björn Pollex    15 年前
    1. 试用使用 RAII-techniques 以避免内存泄漏问题。如果用类似 boost::shared_array 您不必编写显式析构函数来释放内存。
    2. ustring operator=(ustring input) 应该是 ustring operator=(const ustring & input) 避免复制参数。如果将非整型作为只读参数传递,则应该始终这样做。
    3. 使用 shared_array 它也解决了计算大小的问题。

    只是一些提示。另一方面,您的代码非常难以阅读和理解。如果你希望别人能和你一起工作,你真的应该做些什么。使您的名称更具描述性,将重复出现的代码重构为表示其功能的函数。例如,不使用 for -循环复制值,可以使用 std::copy . 你也可以考虑替换你所有的魔法数字(例如 0x1f )常量的名称表示值的语义。