Take this Scheme program as an example (adapted from the LISP programming language page to a more SICP?ish style):
(define (factorial n)
(define (iter n acc)
(if (<= n 1)
acc
(iter (- n 1) (* acc n))))
(iter n 1))
As you can see, the inner procedure "iter" calls itself last in the control flow. This allows an interpreter or compiler to re-organize the procedure which would look like this:
call fact (3)
call iter (3 1)
call iter (2 3)
call iter (1 6)
call iter (0 6)
return 6
return 6
return 6
return 6
return 6
into the more space- (and time-)efficient? variant:
call fact (3) replace arguments with (3 1), jump into "iter" replace arguments with (2 3), re-iterate replace arguments with (1 6), re-iterate replace arguments with (0 6), re-iterate return 6
tail recursion and [tail call]?s in general take far less space because no state save for the calling function's address needs to be saved, neither on the stack nor on the heap.