由于程序员必须编写出到分配和释放存储器的明确的调用,所以用m a l l o c和f r e e完成指针的动态分配和重新分配是管理堆的手工( m a n u a l )方法。相反地,运行时栈则是由调用序列自动地( a u t o m a t i c a l l y )管理。在一种需要完全动态的运行时环境的语言中,堆也必须类似地自动管理。然而尽管在每个过程调用中可以很方便地调度对m a l l o c的调用,但是由于活动记录必须要持续到其所有的引用都消失为止,所以退出时却很难调度对f r e e的调用。因此,自动存储器管理涉及到了前面分配的但不再使用的存储器的回收,可能是在它被分配的很久以后,而没有明确的对f r e e的调用。这个过程称作垃圾回收(garbage collection)。
在存储块不再引用时,无论是直接还是通过指针间接的引用,识别是一项比维护堆存储块的列表复杂得多的任务。标准的技术是执行标识和打扫(mark and sweep)垃圾回收。在这种方法中,直到一个对m a l l o c的调用失败之前都不会释放存储器,在这时将垃圾回收程序激活,寻找可被引用的所有存储器并释放所有未引用的存储器。这是通过两遍来完成的。第1遍递归地顺着所有的指针前进,从所有当前的可访问指针值开始,并标出到达的每个存储器块。这个过程要求额外的位存储标识。另一个遍则线性地打扫存储器,并将未标出的块返回到自由存储器中。虽然这个过程通常要寻找足够的相邻自由存储器以满足一系列的新要求,但存储器仍有可能是非常破碎,故尽管是在垃圾回收之后,大的存储请求仍旧会失败。因此,垃圾回收经常也会通过将所有的分配的空间移到堆的末尾,以及在另一端留下相邻的自由空间的唯一一个大型块而执行存储器压缩(memory compaction)。这个过程还必须在存储器中更新对那些在执行程序时被移掉的区域的所有引用。
标识和打扫垃圾回收有若干个缺点:它要求额外的存储(用于标识),在存储器中的两个遍导致了过程中很大的延迟,有时需要几秒钟,而每一次调用垃圾回收程序又都需要几分钟时间。这对于那些许多涉及到了交互和即时响应的应用程序显然是不合适的。可以通过将可用的存储器分为两个部分并每次只从一个部分中分配存储来对这个过程进行改进。在标识遍时,将所有到达了的块都复制到未被使用的另一半存储器中。这就意味着在存储时不再要求额外的标识位而且一个遍就够了。它还自动地进行压缩。一但位于使用的区域中的所有可到达的块都复制好时,就将使用的和未使用的存储器部分相互交换,而过程依然继续进行。这种方法称作停机和复制( s t o p - a n d - c o p y )或二部空间(two space)垃圾回收。然而它对存储回收中的过程延迟改进不大。
最近又提出了一个大大减少延迟的方法,称为生育的垃圾回收(generational garbage collection),它将一个永久的存储区域添加到前一段描述的回收方案中。将存在时间足够长的被分配的对象只复制到永久空间中,并在随后的存储回收时不再重新分配。这就意味着垃圾回收程序在更新的存储分配时只需要搜索存储器中的很小的一个部分。当然永久存储器也有可能由于不可达到的存储而用尽,但这相对于前面的问题就不那么严重了,这是因为临时存储会很快消失,而可被分配的存储则总会有的。人们已证明了这个处理很好,在虚拟存储系统中尤为如此。