【问题标题】:Does C send method free buffer?C 是否发送方法空闲缓冲区?
【发布时间】:2011-08-02 02:15:26
【问题描述】:

我有一个关于 C 的发送方法的问题。

int send (int socket, void *buffer, size_t size, int flags);

我的代码:

char *buffer = (char *)malloc(100*sizeof(char));
send(s, buffer, 100*sizeof(char), MSG_NOSIGNAL);

现在我想知道是我应该自己释放缓冲区还是 send 方法释放它?

我释放缓冲区的代码:

char *buffer = (char *)malloc(100*sizeof(char));
send(s, buffer, 100*sizeof(char), MSG_NOSIGNAL);
free(buffer);

当我看到错误时,我以为我很快就释放了缓冲区,而 send 方法仍在使用内存。

告诉我。

【问题讨论】:

    标签: c free send


    【解决方案1】:

    send 不会释放缓冲区。你需要释放它。除了它根本不是这样设计的(套接字函数独立于堆函数)之外,send 实际上不会“知道”是否应该释放内存,因为它可能是指向已分配块中间的指针内存或者它可以是指向堆栈数据的指针。

    在发送调用后立即释放缓冲区应该是“安全的”,因为函数会将数据复制到它自己的内部缓冲区。您显示的代码不会导致损坏问题(尽管我怀疑涉及更多代码,因为缓冲区未如图所示初始化)。堆有可能在进程的早期被损坏,直到后来才导致异常(例如,发送后的空闲)。

    send的返回值表示成功发送的字节数(虽然不一定成功传递)。因此,虽然释放它是“安全的”,但如果未全部发送,您将丢失未发送的数据。如果没有发送整个缓冲区,您需要再次调用 send 剩余的金额。

    【讨论】:

    • @Tim:是的,在发送后立即释放它是安全的,尽管您可能想检查发送的返回值。表示成功发送的字节数。
    • 我明白了,但是如果所有字节都成功发送了怎么办?如果有些字节没有发送呢?
    【解决方案2】:

    send() 不会释放缓冲区。如果你有双重释放问题,你应该看看你释放它的地方并检查你是如何到达那里的。

    【讨论】:

      【解决方案3】:

      您可以在send 调用返回后free 缓冲区,注意以下几点:

      • 可能尚未发送整个缓冲区。
      • 该调用返回内核已复制到其自己的缓冲区中的字节数。其余的你应该保留。

      此代码可以帮助您了解正在发生的事情,但您绝不应以此为基础:

      char *buf; // sizeof(*buf) must be 1 for pointer arithmetic
      ssize_t sent = send(fd, buf, len, 0);
      if (sent != -1) { // no error
          // move the unsent bytes to the start of the buffer
          memmove(buf, buf + sent, len - sent);
          // resize the buffer to fit the left over bytes
          buf = realloc(buf, len - sent);
      }
      

      【讨论】:

        【解决方案4】:

        一般来说,如果一个 api 函数会释放一个缓冲区,那将是非常不寻常的。我知道释放缓冲区的唯一功能是“免费”...

        有时,函数会分配您在使用它们后必须释放的内存,例如strdup

        有些函数在使用后不能直接释放缓冲区。例如,在 .Net 中,如果位图的数据指针仍在位图包装器中使用,则无法处置它。

        【讨论】:

        • realloc() 也可以释放从空闲存储区分配的内存,如果传递的大小为零。否则,您是正确的——只有诸如 free() 和 realloc() 之类的堆 API 函数才能释放从空闲存储中获得的内存。
        【解决方案5】:

        从您的描述中听起来好像您的代码在释放指针后使用了指针。有一些很好的、可靠的方法可以解决这类问题,然后是快速破解。这是一个快速破解:

        #define free(p) do { (free)(p); p=(void*)1; } while (0)
        

        您希望包含在头文件或项目的第一行中的此宏替换您对 free 的调用,以便:

        1. 内存仍为 free()'d,符号 (free)(p) 强制 C 编译器将 (free) 评估为函数符号,而不是宏扩展。
        2. 指针设置为不可访问的值 1。未使用值 NULL (0),因为如果通过 NULLfree() 不会抱怨。传递 1 的“指针值”应该会触发错误报告。

        您可能会发现在使用此宏后,您的代码一直在取消引用一个过时的指针。一旦您拥有free'd 内存,指向它的指针将指向相同的内存并暂时指向内存中的相同值——直到第二次使用该内存将这些值擦除。因此,您的程序可能能够使用过时的指针运行几行。当它变得陈旧时将每个指针更改为1 将立即捕捉到这一点。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-09-21
          • 1970-01-01
          • 2011-06-27
          • 2012-09-10
          • 1970-01-01
          • 2014-12-11
          • 2010-11-09
          相关资源
          最近更新 更多