2) VMs avoid crashes upon failures that cause a segmentation fault in native opcodes, with a VM you can keep the process from crashing AND get exact information where and how the problem occurred avoiding debug compiles with symbols and reproducing the error on your local computer.
Right now I use this with my C++ code to get somewhere near the feedback I get from Java (but it requires you to compile with debug): http://move.rupy.se/file/stack.txt
The question you really should ask is why are people using C++? Performance is only required in some parts of engines, to have a VM without GC on top should be default by now (50 years after C and 25 years after Java).
I don’t have anything against Java, but it seems like you lose a lot of the benefits of using when you take away allocation.
Java + WASM is probably what I'll end up with, don't like the AoT step from a distance we'll see.
I'm looking at all Risc/stack op/byte-code, and it's disheartening in how many ways humans can copy the same thing differently.
C#, RISC-V, Java, WASM, ARM, 6502 ASM, uxn, lox the list goes on and on...