程序的运行会消耗内存这一点没疑问吧?
JVM主要是负责内存的动态分配与回收。也就是随着程序的运行,JVM帮我们自动根据程序的代码分配内存来执行程序,与及回收没被使用的内存。
具体以java中的main方法为例。main方法是程序执行的入口。
我们都知道jvm中堆中存放实例,栈中存放方法,栈是后进先出的。
所以main方法的执行,入了栈。
假定main方法内没有内容,那这个过程序就只是简单的一个入栈出栈。程序就结束了。
如果有内容,比如下面这样
那么在元空间与堆中就会分配空间(内存分配),用以存放这些局部变量的实例数据与及类信息等。
这里有个瞬时的概念用以辅助理解这里。就是在这一瞬时,main方法入栈。在运行中,我们去看它的内存分配与回收:栈中被分了一块内存(main方法入栈),堆和元空间被分了内存(类信息与对象实例数据)。
假定执行到第5行,发觉Eden区满了,好了,要触发minorGC。这时候走可达性分析算法的时候,由于当前main方法在入栈中,main内的所有变量都是可达的,那么无论minorGC还是majorGC又或fullGC都回收不了。所以就直接内存溢出异常了。
然后我们调整一下代码
还是这个瞬时,还是执行到第5行时,发觉Eden区满了,触发minorGc。这时,原本在第3行入栈的methoX方法已经出栈,在这个瞬时的栈桢中没有methoX。那么由methoX内产生的变量c对应对象是不可达的。它就可以被内存回收掉。就不会出现内存溢出。
最后,再来回顾下,判断对象是否存活的GC Root可达性分析算法。在某个瞬时,Eden区满了,触发GcRoot可达性分性算法判断哪些对象已废弃。
它的原理是约定好一些根节点(GC Root),主要为4大类:静态变量、常量、当前栈桢局部变量指向的对象、本地方法栈局部变量指向的对象。
由这些Gc Root经由深度优先搜索算法标记上的节点,就是可达的,是不可回收的,其余只要触发GC,就可以被回收掉。