首先看一下JVM内存模型图
(1)调用System.gc时,系统建议执行Full GC,但是不必然执行
(2)老年代空间不足
(3)方法去空间不足
(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存
(5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小
- 引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象相互循环引用的问题
- 可达性分析:从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,不可达对象
> 虚拟机栈(栈帧中的本地变量表)中引用的对象
> 方法区中类静态属性引用的对象
> 方法区中常量引用的对象
> 本地方法栈中JNI(即一般说的Native方法)引用的对象
> 已启动且未停止的java线程
参数 | 默认值 | 作用 |
---|---|---|
MinHeapFreeRatio | 40 | GC后,如果发现空闲堆内存小于整个预估堆内存的40%,则放大堆内存的预估最大值,但不超过固定最大值 |
MaxHeapFreeRatio | 70 | GC后,如果发现空闲堆内存占到整个预估堆内存的70%,则收缩堆内存预估最大值 |
Xms | 物理内存的1/64(<1GB) | 初始堆大小 |
Xmx | 物理内存的1/4(<1GB) | 最大堆大小 |
NewRatio | 2 | 年轻代(包括Eden和两个Survivor区)与年老代的比值 |
NewSize | 1310M | 设置年轻代大小 |
MaxNewSize | 不限 | 设置年轻代大小最大值 |
SurvivorRatio | 8 | Eden区与Survivor区的大小比值 |
MaxTenuringThreshold | 15 | 垃圾最大年龄 |
PretenureSizeThreshold | 0 | 超过这个值直接在old区分配,默认值是0,意思是不管多大都是先在eden中分配 |
在JDK 8中,永久代被删除,类元数据在本机内存中分配。默认情况下,可用于类元数据的本机内存量是无限制的。使用该选项MaxMetaspaceSize可以为用于类元数据的本机内存量设置上限。
metaspace其实由两大部分组成
Klass Metaspace就是用来存klass的,klass是我们熟知的class文件在jvm里的运行时数据结构,不过有点要提的是我们看到的类似A.class其实是存在heap里的,是java.lang.Class的一个对象实例。这块内存是紧接着Heap的,和我们之前的perm一样,这块内存大小可通过-XX:CompressedClassSpaceSize参数来控制,这个参数前面提到了默认是1G,但是这块内存也可以没有,假如没有开启压缩指针就不会有这块内存,这种情况下klass都会存在NoKlass Metaspace里,另外如果我们把-Xmx设置大于32G的话,其实也是没有这块内存的,因为会这么大内存会关闭压缩指针开关。还有就是这块内存最多只会存在一块。
NoKlass Metaspace专门来存klass相关的其他的内容,比如method,constantPool等,这块内存是由多块内存组合起来的,所以可以认为是不连续的内存块组成的。这块内存是必须的,虽然叫做NoKlass Metaspace,但是也其实可以存klass的内容,上面已经提到了对应场景。
Klass Metaspace和NoKlass Mestaspace都是所有classloader共享的,所以类加载器们要分配内存,但是每个类加载器都有一个SpaceManager,来管理属于这个类加载的内存小块。如果Klass Metaspace用完了,那就会OOM了,不过一般情况下不会,NoKlass Mestaspace是由一块块内存慢慢组合起来的,在没有达到限制条件的情况下,会不断加长这条链,让它可以持续工作。
元空间的特点
- 充分利用了Java语言规范中的好处:类及相关的元数据的生命周期与类加载器的一致。
- 每个加载器有专门的存储空间
- 只进行线性分配
- 不会单独回收某个类
- 省掉了GC扫描及压缩的时间
- 元空间里的对象的位置是固定的
- 如果GC发现某个类加载器不再存活了,会把相关的空间整个回收掉
元空间的内存分配模型
- 绝大多数的类元数据的空间都从本地内存中分配
- 用来描述类元数据的类(klasses)也被删除了
- 分元数据分配了多个虚拟内存空间
- 给每个类加载器分配一个内存块的列表。块的大小取决于类加载器的类型; sun/反射/代理对应的类加载器的块会小一些
- 归还内存块,释放内存块列表
- 一旦元空间的数据被清空了,虚拟内存的空间会被回收掉
- 减少碎片的策略
参考: [1] 深入理解Java虚拟机第二版