I would think, since output is popped off the stack, that there wouldn't be any need. Am I missing something?
Yes, you're right. But the stack basedness is just a part of the whole story. For example, the Java bytecode interpreter is stack-based as well (the compiled code works -- for efficiency reasons -- differently). This tells us, that any language can be transformed into a stack language.
What matters are the objects outside of the stack, those who can outlive the current method execution. As long as the language has nothing like
new, there are no such objects and you need no
delete nor GC.
A language lacking dynamic memory allocation is quite limited in its usefulness.
Garbage collection is required if the language is going to support dynamic data structures inherently. Which is almost a necessity if you want to do anything beyond the level of C. Without it you are stuck with only fixed sized data structures and managing memory yourself. That's what original Forth does of course, but it's probably not something you'd want to do today unless your are only doing low-level systems coding.
Garbage collection is not needed if the language uses static allocation instead of stack allocation. For example Fortran 77 with the -s (static storage) option allocates all memory when the program starts, therefore no memory allocation occurs at runtime to be freed. While it takes some discipline, it is possible to write programs, especially simulations to use static memory allocation. Static allocation removes any memory leaks, and leads to terrific cache performance since the compiler can use static analysis to determine what to load into cache.