方法区用于存放已被加载的类的信息,常量,静态变量即时编译器编译后的代码等数据
方法区–>动态扩容–>OutOfMemoryError
JDK8开始移除永久代
JVM中的堆一般分为:新生代、老年代、永久代
新生代:
用来存放新生的对象,一般占据1/3的空间由于频繁创建对象,所以新生代会频繁出发MinorGC进行垃圾回收
新生代:Eden区、ServivorFrom、ServivorTo三个区
- Eden区:java新对象的出生地(如果新创建的对象占用内存很大,直接分配到老年区)。当Eden内存不够的时候,就会触发MinorGC对新生代进行一次垃圾回收
- ServivorTo:保留了一次MinorGC过程中的幸存者
- ServivorFrom:上一次GC的幸存者,作为这一次GC的被扫描者
当JVM无法为新对象分配内存空间时(Eden满了),Minor GC被触发,因此新生代空间占有率越高,Minor GC越频繁
Minor GC的过程:采用复制算法:
1:首先,把Eden和ServivorFrom区域中存活的对象复制到ServivorTo区域【如果有对象的年龄达到老年的标准,一般为15,则赋值到老年区】
2:同时把这些对象的年龄增加1,如果ServivorTo不够位置就放到老年区
3:然后清空Eden和ServivorFrom中的对象,最后,ServivorFrom 和 ServivorTo互换,原ServivorTo成为下一次GC的ServivorFrom区
老年代:老年代对象比较稳定,所以Major GC不会频繁执行
在进行Major GG前一般都先进行了一次Minor GC,使得有新生代的对象晋入老年代,导致空间不够用才触发,当无法找到足够大的连续空间分配给新创建的较大对象时也会提前触发一次Major GC进行垃圾回收腾出空间
Major GC采用标记-清除算法:
1:首先扫描一次所有老年代,标记存活的对象
2:回收没有标记的对象
Major GC耗时比较长,因为要扫描再回收,Major GC会产生内存碎片,为了减少内存损耗,我们一般进行合并或者标记出来,方便下次直接分配
当老年代也满了装不下了,就会抛出OOM【out of memory】异常
永久代:指内存的永久保存区域,主要存放class和Meta(元数据)信息
class在被加载的时候被放入永久区域,它和存放实例不同,GC不会在主程序运行期间对永久区域进行清理,这导致永久代区域随着类加载的class增多而胀满,最终抛出OOM(Out Of Memory)异常
在java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代
元空间
本质与永久代类似,都是对JVM规范中方法区的实现,不过元空间与永久代之间最大的区别在于:元空间不在虚拟机中,而是使用本地内存,因此,默认情况下元空间的大小仅受本地内存限制,类的元数据放入native memory,字符串池和类的静态变量放入java堆中,这样可以加载多少类的元数据就不再由MaxPermSize控制,而是由系统的实际可用空间来控制
Major GC 和 Full GC 的区别:
Full GC:收集young gen、old gen、perm gen
Major GC:有时又叫 old gc ,只收集 old gen
PermGen space 与 方法区: