Not sure if this will help, since I guess your question comes from a specific problem that you have found.
To my understanding, memory leaks occur when an object's life cycle isn't a 'clean' operation. That is, the object is created, some memory is allocated for it and more resources can be allocated during calls to its methods. When this object is not longer needed, and garbage collected, there are some cases in which not all the resources used are deallocated. Don't know how internally works (reference counting?)
From my experience, there are some behaviors that could seem memory leaks although they aren't technically such: imagine a Java object in which one of its members is just a long integer that is an identifier for a big amount of memory allocated in the native C code when the object is created. Also suppose that this native memory is correctly deallocated when the object is destroyed (as there is a native call to free the memory associated with that long integer).
If during an application lifecycle this object is locally declared in an inner loop (so it is 'created' and 'forgotten' very often), the garbage collector will only see its 'Java size ' (the resources for a standard Java object plus its members), so it will not be high priority when it needs to free Java memory. If we take this situation to the limit (object locally declared in an inner loop), it can lead to crashes.