One of the problems is that nearly everything is an object so you end up with a lot of pointers which takes up additional space. Garbage collection isn't free either.
In this case it would have made sense to go with C++ and allocated as much as possible on the stack. It is cheaper memory wise (because you don't have to keep whatever malloc requires around and because they are removed as soon as you are done with it) and it gives better performance too.
For what you can't allocate on the stack, you a smart pointer.
There are of course pitfalls here -- smart pointers (via reference counting) can be slower than garbage collection and they have trouble dealing with cycles. You may also have to take special care if they are shared across threads.