JVM运行时内存区域划分

329 阅读3分钟

JVM运行时内存区域划分

JVM运行时内存说的就是JVM的堆,他是垃圾收集器进行垃圾回收的最主要的内存区域,我们每次创建的对象和产生的数据都被存储在堆中

Java堆从GC的角度去看,可以分为三个区域,分为是新生代,老年代,永久代

其中新生代占1/3的堆空间,老年代占2/3的堆空间,永久代占得很少,就不进行划分了,他也占了,但是很少很少,新生代占的1/3又分为Eden区(占比8/10),ServivorFrom区(占比1/10),ServivorTo区(占比1/10),大概的占比图如下

\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mq0vPeyG-1584457393424)(C:\Users\gx\AppData\Roaming\Typora\typora-user-images\image-20200317222622128.png)\]

新生代

我们新创建的对象(除了大对象,大对象是直接放进了老年代)都是放在新生代中的,由于JVM会频繁的创建对象,所以就会频繁的触发GC,新生代时的GC叫做MinorGC

大对象的定义和JVM版本、堆大小、内存回收策略有关,一般都是在2KB~128KB之间

新生代中分为了三个区域,分别时EnedServivorToServivorFrom

Ened:我们新创建的对象首先就会放入到Ened区,当Ened区的内存不足时会触发MinorGC

ServivorTo:存放上一次MinorGC的幸存者,也是下一次的ServivorFrom区

ServivorFrom:存放的是上一次MinorGC的幸存者,在上一次中他是ServivorTo区,他在这一次中充当被扫描者的角色

其实从上面的几个介绍来看,可能就只能理解Ened是干嘛的,如果了解了MinorGC的流程就会很清楚了

MinorGCC的具体过程

MinorGCC的具体过程是采用复制算法实现的,具体步骤如下:

1、首先会把Ened区与ServivorFrom区中存活的对象复制到ServivorTo区中去。

这里会将达到了老年代的标准的对象复制到老年代区去,然后整体对象的标准年龄+1(15为老年代的标准),如果ServivorTo的内存不足的情况,存活的对象就直接全部复制到老年代

2、清空Ened区与ServivorFrom区

3、将ServivorTo区与ServivorFrom区互换,原本的ServivorTo区成为了下一次ServivorFrom区,然后下一次他里面的对象又要被复制到下一次的ServivorTo区中区

老年代

老年代主要存放的就是长生命周期的对象和大对象,不会频繁出发GC了,老年代的GC叫做MajorGC,在进行老年代GC之前,他会调用新生代的GC一次,然后将那些要存放到老年代的对象都复制过来,如果在新生代GC后,老年代的空间不足,那么就会触发MajorGC

老年的GC采用的是标记清除法,他会去扫描所有的对象并且标记存活的对象,然后回收掉所有未标记的对象。MajGC因为要扫描所有的对象,所以耗时会较长,而且标记清除法也容易产生内存碎片,老年代内存空间不足时,会触发OOM

永久代

永久代主要保存的是Class和元数据信息,Class在类加载时被放入永久代,永久代不会触发GC,因为他不会GC,所以他的内存会随着加载Class文件的增加而增加,加载的Class文件过多时就会OOM,比如Tomcat引用的jar文件过多时就会导致JVM内存不足而无法启动

在1.8之前,永久代是用的JVM虚拟机的内存,所以他的实际可用内存就受到了JVM内存的限制,1.8之后用的是操作系统的内存