Another thing to note about garbage-collected languages (like Java with the G1 collector) is that blocks of memory will often be *copied* to other parts of the physical memory as part of compaction phase [1] (see quote), in order to be able to provide large segments of sequential space. Since the GC is designed with performance in mind rather than security, the original copies are not zero'd as part of this compaction, and instead their raw data will potentially stay in memory indefinitely until overwritten by another part of the application, and will not be zero'd upon termination of the application. Because of this, even with meticulous tracking of references and "raw" memory access only, GC'd applications can leave traces of secrets on memory. There may be workarounds for this by exclusively using "Unsafe" methods, but that drastically limits your API-interoperatility with libraries and such.
> G1 reclaims space mostly by using evacuation: live objects found within selected memory areas to collect are copied into new memory areas, compacting them in the process. After an evacuation has been completed, the space previously occupied by live objects is reused for allocation by the application.
[1] https://docs.oracle.com/en/java/javase/18/gctuning/garbage-f...