(1)虚拟机栈:
描述的是方法执行时的内存模型,是线程私有的,其生命周期与线程一致,方法执行时入栈,执行完出栈,所以这块区域不需要GC;
(2)本地方法栈:
与虚拟机栈相似,主要区别在于虚拟机栈为虚拟机执行方法时服务,而本地方法栈为虚拟机执行本地方法时服务。这块区域也不需要GC;
(3)程序计数器:
线程独有的,可以把它看成线程执行时的信号指示器。记录这些数字(指令地址)有啥用呢,我们知道 Java 虚拟机的多线程是通过线程轮流切换并分配处理器的时间来完成的,在任何一个时刻,一个处理器只会执行一个线程,如果这个线程被分配的时间片执行完了(线程被挂起),处理器会切换到另外一个线程执行,当下次轮到执行被挂起的线程(唤醒线程)时,怎么知道上次执行到哪了呢,通过记录在程序计数器中的行号指示器即可知道,所以程序计数器的主要作用是记录线程运行时的状态,方便线程被唤醒时能从上一次被挂起时的状态继续执行,需要注意的是,程序计数器是唯一一个在 Java 虚拟机规范中没有规定任何 OOM 情况的区域,所以这块区域也不需要进行 GC;
(4)永久代:
java8之前的概念实际上指的是HotSpot虚拟机上的永久代,它用永久代实现了JVM规范定义的方法区功能,只要储存类的信息、常量、静态变量、即时编译器编译后的代码等,这部分由于是在堆中实现,受GC的管理,不过由于永久代有 -XX:MaxPermSize的上限,所以如果动态生成类(将信息放入永久代)或大量执行String.intern(将字符串放入永久代的常量区),很容易造成OOM,有人说可以把永久代设置足够大,但很难确定一个合适的大小,受类数量、常量数量的大小的影响很大。java8之前的永久代是需要进行GC的。
(5)本地内存:
线程共享区域,在java8中,本地内存也就是我们常说的堆外内存,包含元空间和直接内存,java8这一区域不需要GC,原因的是什么呢?java8取消永久代,将方法区移到了本地内存中的元空间中,这样方法区就不受JVM控制了,也不会进行GC,也因此提升了性能(发生GC会发生Stop The Word,性能会受到一定影响,后文会提到),也就不存在由于永久代限制大小而导致的OOM异常了(加上总内存1G,JVM被分配内存100M,理论上元空间可以分配1.9G空间大小足够),也方便在元空间中统一管理。综上,不需要GC;
(6)堆:
对象实例和数组都是在堆上分配的,GC也主要对着两类数据进行回收。