在咱们使用Java语言的时候,底层打交道最多的时候就是堆了,它也是Java虚拟机里面比较重要的部分,相比于Java的栈结构,Java的堆结构中多了垃圾回收的机制(毕竟存了很多实实在在的对象),这也是让人十分头秃的一个部分,下面就简单的介绍一下Java的堆一些知识。
运行虚拟机的堆的参数设置
在运行Java实例的时候,环境总是给默认配置了一些默认的虚拟机参数,然而根据自己的项目需求,需要使用的堆的参数总是变化的,这时候就需要自己配置合适的参数
-Xms表示堆区的起始内存,等价于-XX:InitialHeapSize
-Xmx表示堆区的最大内存,等价于-XX:MaxHeapSize(堆区大于-Xmx所指定的最大内存,会抛出OOM)
一般在实际使用的时候都把初始和最大的堆参数设置成一样的,避免动态变化堆大小的时候对性能产生影响
默认的情况下,初始的内存大小会设置为物理内存大小的1/64,最大内存大小会设置成物理内存的1/4,这个可以获取Runtime实例进行读取,或者直接使用
java -XX:+PrintFlagsFinal -version | findstr /i "HeapSize PermSize ThreadStackSize"
查询
堆内存的分区
如图可见,JDK7之前逻辑上分为新生区,养老区,永久区
JDK8之后逻辑上分为新生区,养老区,元空间
此外在上述中设置的-Xmx只能分配Young和Old区,这个可以在运行时候使用
JVirtualVM
命令查看,或者在配置虚拟机参数的时候使用-XX:+PrintGCDetails
查看分配的空间默认的新生区和养老区比例为1:2,这个可以使用
-XX:NewRatio=养老区/新生区
进行配置
细分新生区
新生区有可以分为
Eden
区和俩Survivor
区,这个比例默认为8:1:1,可以通过-XX:SurvivorRatio=Eden/Survivor比例
调整
简述GC
上面介绍了一点堆空间分区的概念,这个分区主要是后面进行GC垃圾回收的时候管理方便。当然,不同的回收算法有不同的细则,这里介绍一下常用的一种回收机制。
一般对象都是先在Eden内新建出来的(当对象过大的时候会有特殊情况)
在Eden中空间不足的时候会触发Young GC,进行一次垃圾回收,并且会将不被回收的放入Survivor一个区中 ,并且对其标记
当循环多次之后,当标记为15(可以修改,
-XX:MaxTenuringThreshold=
范围是0-15),然后就会把他们送入养老区
在其他亿些情况的时候会触发Full GC/Major GC,就会对大部分的堆空间进行收集,此时当空间不足后,就会抛出错误OOM(这就是可恶的OOM)