这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战
一、概述
对于 Java 程序员而言,在虚拟机自动内存管理机制下,程序是不需要我们手动去做垃圾回收的。不过在我们将内存控制权利交给 Java 虚拟机的同时,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会是一个非常艰巨的任务,因此JAVA的垃圾回收机制也是我们学习java的重点,同样也是我们面试常问的知识点。
二、内存区域简介
Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。JDK 1.8 和之前的版本略有不同。
其中 线程私有的:
- 程序计数器:用来存储下一条需要执行的字节码指令,同时也为线程执行做记录,保障线程切换后能恢复到正确的执行位置。
- 虚拟机栈:Java 虚拟机栈是由一个个栈帧组成,而每个栈帧相当于一个线程,其中都拥有:局部变量表、操作数栈、动态链接、方法出口。这些都是线程私有的
- 本地方法栈:用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。
线程共享的:
- 堆:Java 堆是垃圾收集器管理的主要区域,因此也被称作GC 堆(Garbage Collected Heap)
- 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- 直接内存 (非运行时数据区的一部分)
其中方法区在1.8版本的时候改为元空间,这样做的原因有两点
-
永久代设置空间大小很难确定。一个应用动态加载的类的多少是很难确定的,如果永久代设置的过小,会频繁触发FullGC,并且可能会出现OOM。而元空间的大小只收本地内存限制,这样出现OOM的机会比较小。
-
对永久代进行调优十分困难。调优是为了减少FullGC,如果永久代频繁触发FullGC,会使永久代调优变得困难。
而将方法区转换为元空间,增大了方法区,让方法区变得和内存一样大,可以减少了内存溢出等问题的出现(但并不代表不会出现)。