没有free()的malloc()调用的真正后果是什么?它能让一个程序变得疯狂吗,比如永远的循环?

没有free()的malloc()调用的真正后果是什么?它能让一个程序变得疯狂吗,比如永远的循环?,c,linux,32-bit,icc,C,Linux,32 Bit,Icc,我目前的课程有一个大问题。在循环中,两个函数如果我在这个循环中调用另一个函数,我会得到一个永久循环!甚至一个printf(“bah”)给出一个永久循环 这给了正常的执行 //size = 10 (example) while(size > 0) { a(); // decrement by 2 b(); // decrement by 2 } 但是 给一个永远的循环。唯一不同的是putchar()调用 很难假设什么,但对发生的事情有什么想法 a()和b()`函数基本上做的是: 从

我目前的课程有一个大问题。在循环中,两个函数如果我在这个循环中调用另一个函数,我会得到一个永久循环!甚至一个
printf(“bah”)给出一个永久循环

这给了正常的执行

//size = 10 (example)
while(size > 0) {
  a(); // decrement by 2
  b(); // decrement by 2
}
但是

给一个永远的循环。唯一不同的是
putchar()
调用

很难假设什么,但对发生的事情有什么想法

a()和
b()`函数基本上做的是:

从数组中获取两个结构,按
1
printf()
减量
size
。这样的结构只有在程序结束时才被释放

我将这部分代码发布到tro,以了解(可能发生的)情况。这部分代码中的所有代码都非常大(请张贴在这里供我们阅读)

编辑:

下面是一个最小的
a()
b()
实现:

void a(void) {
  foo_t* f = top;
  while(f->y == STATE_X) {
  get(&a); get(&b); /* it's equivalent to pop() in a linked list. size is size=size-1 in each get call() */
  printf("%d,%d\n",a->x,ab->x);
  f = f->next;
 }
 top = f;
}

void a(void) {
  foo_t* f = top;
  while(f->y == STATE_Y) {
  get(&a); get(&b); /* it's equivalent to pop() in a linked list. size is size=size-1 in each get call() */
  printf("%d,%d\n",a->x,ab->x);
  f = f->next;
 }
 top = f;
}
get()
-在我的上下文中相当于
pop()

top
-指向从堆栈处理的最后一个
struct footype

size
-堆栈上当前元素的计数


struct footype
也被实现为链接的。这里有一个
prev
next
,指向它的前一个和下一个成员。

如果我们完全按照您所说的代码,没有显示内存分配,但是永远不会释放——那么在程序结束之前,内存将保持分配状态。如果继续分配更多内存而不释放任何内存,最终将耗尽…此时
malloc
可能开始失败并返回空指针。(当然,如果按照C标准,试图通过空指针访问内存可能会导致各种各样的怪事。不过,Linux中最常见的结果是segfault。)

但是,如果没有
ulimit
设置,您可能也会耗尽所有交换空间,这可能会导致最后的速度大幅降低。当然,在您的进程中使用所有的内存,会将其从其他进程中移除。最终,有两件事可能会发生:

  • 其他进程可能开始无法分配内存…如果它们没有考虑到这一点,它们可能会中断

  • Linux会有意地分配虚拟内存——基本上,内存页既不是由RAM支持,也不是由交换空间支持。(原因有点复杂,但在上下文中是有意义的。)只有当一个进程试图实际使用该内存时,内核才会为它寻找一些RAM。如果没有可用RAM和交换空间,内核将杀死现有进程以回收其虚拟内存

    (如果它走得那么远,就会有一个算法来决定要杀死哪个进程。它通常会选择最糟糕的进程——在这种情况下,这可能是你的进程。)

不过,这与损失的程度有关。你会把事情拖慢一点,弄乱其他进程,可能会杀死其中一个进程(很可能是你的进程)

有一件事它不会做,至少它自己不会,那就是使循环永远继续下去。为了使其发生这种情况,程序必须(1)检查失败,(2)循环不断地重试失败的操作,直到成功,而不改变与操作相关的任何内容


这里还发生了一些其他的事情。

如果我们完全按照你所说的代码去做,而代码没有显示内存已分配,但从未释放,那么内存将一直被分配,直到程序结束。如果继续分配更多内存而不释放任何内存,最终将耗尽…此时
malloc
可能开始失败并返回空指针。(当然,如果按照C标准,试图通过空指针访问内存可能会导致各种各样的怪事。不过,Linux中最常见的结果是segfault。)

但是,如果没有
ulimit
设置,您可能也会耗尽所有交换空间,这可能会导致最后的速度大幅降低。当然,在您的进程中使用所有的内存,会将其从其他进程中移除。最终,有两件事可能会发生:

  • 其他进程可能开始无法分配内存…如果它们没有考虑到这一点,它们可能会中断

  • Linux会有意地分配虚拟内存——基本上,内存页既不是由RAM支持,也不是由交换空间支持。(原因有点复杂,但在上下文中是有意义的。)只有当一个进程试图实际使用该内存时,内核才会为它寻找一些RAM。如果没有可用RAM和交换空间,内核将杀死现有进程以回收其虚拟内存

    (如果它走得那么远,就会有一个算法来决定要杀死哪个进程。它通常会选择最糟糕的进程——在这种情况下,这可能是你的进程。)

不过,这与损失的程度有关。你会把事情拖慢一点,弄乱其他进程,可能会杀死其中一个进程(很可能是你的进程)

有一件事它不会做,至少它自己不会,那就是使循环永远继续下去。为了使其发生这种情况,程序必须(1)检查失败,(2)循环不断地重试失败的操作,直到成功,而不改变与操作相关的任何内容


这里还发生了一些事情。

我认为你应该发布更多的代码不,内存分配(除非你的内存用完了,那么…这取决于你的代码)不会导致无限循环。您在函数内部做了一些不好的事情(可能是指针,除非“大小”有错误)。
void a(void) {
  foo_t* f = top;
  while(f->y == STATE_X) {
  get(&a); get(&b); /* it's equivalent to pop() in a linked list. size is size=size-1 in each get call() */
  printf("%d,%d\n",a->x,ab->x);
  f = f->next;
 }
 top = f;
}

void a(void) {
  foo_t* f = top;
  while(f->y == STATE_Y) {
  get(&a); get(&b); /* it's equivalent to pop() in a linked list. size is size=size-1 in each get call() */
  printf("%d,%d\n",a->x,ab->x);
  f = f->next;
 }
 top = f;
}