这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战
堆
特点:
- 虚拟机管理的内存最大的一块
- 所有线程共享(TLAB例外)
- 虚拟机启动时创建
- 唯一目的事存放对象实例
- 垃圾收集器的主要区域
- GC堆。分代收集算法。细分为新生代和老年代, 新生代分为Eden空间, From Survivor空间, To Survivor空间。
- 物理存储上不连续的,逻辑上连续的,大小可调节的(-Xms和-Xmx空间)
- 方法结束后, 堆中内存不会马上移除仅仅在垃圾回收的时候才移除
- 如果在堆中没有内存完成实例分配,并且无法扩展, 抛出OutOfMemoryError异常。
设置堆空间大小
-Xmx20m -Xms5m
分类
年轻代 Eden surivivor0 surivivor1
老年代 old
- young Gen: 年轻代主要存放新创建的对象,内存大小相对比较小, 垃圾收集比较频繁,分成1个 Eden和2个Survivor
- Tenured Gen: 存放JVM认为生命周期比较长的对象,内存大小相对比较大, 垃圾回收也没那么频繁
-XX:NewRatio=2 // 新生代占堆的1/3
-XX:SurvivorRatio=8 // Survivor占新生代的1/8
对象分配过程
- new的对象先放在Eden区
- 当Eden区填满时, 需要创建对象, JVM垃圾回收器对Eden进行垃圾回收(Minor GC), 将Eden区不再被其他对象引用的对象销毁,加载新的对象到Eden区
- 将剩余的对象移动到S0 区
- 如果再触发垃圾回收, 上次S0区的如果没有回收, 放到S1区
- 如果再次垃圾回收,此时会重新返回S0区,接着再去S1区
- 如果累计次数到达默认15次, 就会进入Tenured区。参数是-XX:MaxTenuringThreshold = N
- Tenured内存不足, 会再次触发GC: Major GC 进行Tenured区的清理, 如果执行了Major GC, 仍然没法保存对象, 就会报OMM异常。
堆GC
GC分两种: 一种是部分收集器Partial GC,一种是整堆GCFull GC
部分收集器: 不完整的堆收集, 分为
- 新生代收集 Minor GC / Young GC
- 老年带收集 Major GC/ Old GC(CMS GC 单独回收老年代)
- 混合收集 Mixed GC 收集整个新生代及老年代 G1混合回收
整堆回收 Full GC: 收集整个java堆和方法区的垃圾回收器
年轻代GC触发条件:
- 年轻代空间不足, 这里指的是Eden满, Survivor不满
- Minor GC 会引发STW
老年代GC(Major GC)触发条件:
- 老年代空间不足, 尝试触发MinorGC, 如果还是不足,触发Major GC, 如果Major GC , 内存还不足,OOM, Major GC速度比Minor GC慢10倍
Full GC 触发:
- 调用System.gc(), 不是立刻执行
- 老年代空间不足
- 方法区空间不足
元空间
本地内存,存储类的元信息。
-XX:MetaspaceSize //初始空间大小,达到该值会触发垃圾回收进行类型卸载,GC也会对该值进行调整,如果释放了大量空间,就适当降低,如果释放了很少空间, 就在不超过MaxMetaspaceSize时, 适当提高该值
-XX:MaxMetaspaceSize // 最大空间, 默认没有限制, 最大可利用空间就是整个系统的内存可用空间, 没有设置,就可能导致空间不断扩展,导致内存不足, 出现swap内存被耗尽, 进程直接被kill掉。如果设置了, 当剩余空间不足时, 会抛出OutOfMemoryError
-XX:MinMetaspaceFreeRatio //GC后最小的metaspace剩余空间容量的百分比, 减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio //GC后最大的metaspace剩余空间容量的百分比,减少为释放空间导致的垃圾收集
jps
jinfo -flag MetaspaceSize pid
方法区
存储被虚拟机加载的类型信息,常量,静态常量, 即时编译器编译后的代码缓存数据。元空间和永久代是方法区具体的落地实现。
- 线程共享
- JVM启动创建, 物理内存可以不连续
- 大小可以选择固定大小或动态变化
- 决定了可以保存多少类
常量池
- 字节码文件内部包含了常量池
- 方法区内部包含了运行时常量池
常量池存放编译期间生成的各种字面量和符号引用
运行时常量池是常量池表在运行时的表现形式。
直接内存
堆外内存, 通过存储在Java堆中的DirectByteBuffer对象作为内存的引用进行操作。
- 改善了堆过大时垃圾回收效率,减少停顿, FullGC 会扫描堆内存,回收效率和堆大小成正比
- 减少了Native堆和JVM堆拷贝过程
- 可以突破JVM内存限制
-XX:MaxDirectMemorySize //不去指定默认和堆最大值一样
越过DirectByteBuffer直接通过反射获取Unsafe类进行内存分配,如果使用DirectByteBuffer分配内存会抛出内存溢出异常,但是抛出时并没有真正向操作系统申请分配内存,而是计算得知无法分配就直接抛出异常, 真正分配方法是Unsafe::allocateMemory