Assembly MIPS-释放动态分配的空间(堆)

Assembly MIPS-释放动态分配的空间(堆),assembly,mips,mars-simulator,Assembly,Mips,Mars Simulator,我正在尝试释放动态分配的堆内存空间 我试过运行这段简单的代码,但总是遇到同样的错误: “请求(-40)是负堆数量(系统调用9)” 有人能帮我理解为什么它不起作用吗? 有没有其他释放空间的方法?MARS不支持带有否定参数的sbrk,正如您在源代码中看到的那样 因此,据我所知,在MARS中运行代码时,没有办法显式释放动态分配的内存。如果使用负的sbrk释放堆内存,基本上将堆变成堆栈,因为只有最后的内存可以返回——这不是堆的真正意义。在堆中,我们希望能够释放任意对象,而不仅仅是最后的对象 因此,问题是

我正在尝试释放动态分配的堆内存空间

我试过运行这段简单的代码,但总是遇到同样的错误:

“请求(-40)是负堆数量(系统调用9)”

有人能帮我理解为什么它不起作用吗?
有没有其他释放空间的方法?

MARS不支持带有否定参数的
sbrk
,正如您在源代码中看到的那样


因此,据我所知,在MARS中运行代码时,没有办法显式释放动态分配的内存。

如果使用负的
sbrk
释放堆内存,基本上将堆变成堆栈,因为只有最后的内存可以返回——这不是堆的真正意义。在堆中,我们希望能够释放任意对象,而不仅仅是最后的对象

因此,问题是:

  • 为什么需要释放堆内存
  • 你真的可以像堆栈一样使用堆吗

您可以实现
malloc
free
。尽管由于它们的通用性和性能考虑,这些功能通常非常复杂,但编写一个简单、缓慢的功能非常容易,特别是如果您了解应用程序及其有限的需求

真正通用的
malloc
/
free
使用收集空闲块的数据结构。
malloc
首先搜索满足请求的块,分发现有空闲块或使用sbrk。
free
将块返回集合(当然还有更多内容:分割大块、合并空闲块……)


但是,如果您可以像堆栈一样使用堆,则可以维护两个指针,一个指示空闲内存的开始位置,另一个指示空闲内存的结束位置。释放最近分配的内存(如
sbrk(-400)
)将使空闲内存开始指针减少400。分配内存将使空闲内存开始指针增加所需的量,同时在需要时移动空闲内存结束指针(使用仍然需要的任何大小的
sbrk

这就是堆在实际操作系统中的工作方式。real
malloc
实现(就像在glibc中一样)一定要使用sbrk进行小的分配(
mmap
进行大的分配,这样内存就可以立即免费返回操作系统)。事实上,一次未混合的分配可以阻止一大堆小的分配通过
sbrk
返回操作系统。但是一个适当的malloc实现管理它自己的空闲列表,所以应用程序总是可以释放它分配的任何东西,这只是一个是否可以返回操作系统的问题。但是从操作系统的角度来看,移动break-fwd/back就是sbrk的意思。所以我想,区别在于MARS提供了一些玩具系统调用,这些调用做标准库通常会做的事情,但没有提供malloc实现,只有sbrk。从应用程序POV来看,这不是你想要堆分配器做的。我认为这只是术语问题这让我对这个答案中的措辞感到困扰;“heap”不是一个非常具体的术语;我猜你用它来表示一般的动态分配,但不是说在
sbrk
之上实现
malloc
,而是假设一个薄包装器。@PeterCordes,我接受你关于“heap”的观点无论是从操作系统的角度还是从应用程序的角度来看,都不明确。不过,我确实提到了在malloc中使用sbrk,即malloc作为sbrk顶部的一个层。我不确定我是否理解您想要的顶部与薄包装的区别。所谓“薄包装”,我的意思是
malloc(20)
=
sbrk(+20)
,free需要知道大小。“在顶部”我指的是一个用户空间空闲列表,就像一个真正的malloc实现,在后台使用
sbrk
在空闲列表为空时获得更多核心。(如果空闲列表大于某个阈值,并且在中断的高端有一个连续的空闲块,则在可能的情况下,将部分空闲块返回操作系统。正如您所说,从未释放的分配确实会阻止malloc实现更早地取消映射。)
.text
li $v0,9
li $a0,40
syscall

li $v0,9
li $a0,-40
syscall