Memory leaks in Java can occur due to objects remaining reachable even when no longer needed. The four main causes are unknown references, long-living objects, failure to clean up native resources, and bugs. To detect leaks, one can use verbose GC logging, monitor the Java process, dump the heap to analyze which objects are retaining others, and use profiling tools. Profiling works by insertion of code, sampling, or instrumenting the virtual machine and helps identify where time is being spent and what objects are being allocated.