not really you just need to be able to allocate memory. Since infinite-memory computers aren't readily available on this plane of existence, most lisp-like languages scan the heap for unreachable objects and returning them to the available memory, but you could mix and match many other techniques like memory regions, borrow checker bullshit (buzzword ready!), reference counting, an unholy procedure to free your conses manually (cnile's choice!), or the noble technique called "bump allocate until you run out of memory or the program finishes and you can release the entire heap as garbage" (which i think would actually be a pretty good idea in certain niche cases)
there are probably 7 more of them that i missed because my knowledge of memory allocation techniques is rather limited
i think for lispy languages there are three main ways to go:
- have the programmer insert some extra information about how that memory is being used (slightly tedious)
- "memory is infinite as long as i don't cons the last byte of it" (toy compilers and certain extremely niche cases)
- hypothetical super-advanced sufficiently smart compiler that can infer all the possible memory lifetimes in your program and insert deallocation commands in the perfect places (i will be excited to use this compiler to compile gnu hurd 1.0 in 45 years when they are both finally done)
personally i think option 1 is probably the most sane as far as having a working implementation before everybody here dies of old age, and is also much more practical than option 2 letting you only write programs that last for a few fractions of a second of cpu time