堆结构详解
新生区:
类诞生、生长、以及可能死亡的地方
伊甸园:所有对象的实例化都是在伊甸园产生的
幸存区:伊甸园中经过垃圾回收后还存活的对象会进入到幸存区
老年区:
新生区中经过垃圾回收后还存活的对象会进入到老年区
永久区:
存储的是Java运行时的一些环境或类信息,JVM被关闭后会释放这个区域的内存,不存在垃圾回收
永久区是逻辑上存在但是物理上不存在的一片区域
jdk 1.6 之前:名为永久代,此时常量池在方法区中
jdk 1.7:名为永久代,但永久代慢慢退化,此时常量池在堆中
jdk 1.8 之后:名为元空间,此时常量池在元空间中
//查看堆内存具体各区域所占空间大小,本例中虚拟机的总内存为2M
//查看虚拟机的总内存,代码如下
long totalMemory = Runtime.getRuntime().totalMemory();
//输出结果:虚拟机的总内存为:2.0MB
System.out.println("虚拟机的总内存为:" + (totalMemory/(double)1024/1024) + "MB");
//打印GC详细信息
Heap
PSYoungGen total 1536K,
used 1455K [0x00000000ffd80000, 0x00000000fff80000, 0x0000000100000000)
eden space 1024K,
94% used [0x00000000ffd80000,0x00000000ffe71e10,0x00000000ffe80000)
from space 512K,
95% used [0x00000000fff00000,0x00000000fff7a020,0x00000000fff80000)
to space 512K
0% used [0x00000000ffe80000,0x00000000ffe80000,0x00000000fff00000)
ParOldGen total 512K,
used 128K [0x00000000ff800000, 0x00000000ff880000, 0x00000000ffd80000)
object space 512K,
25% used [0x00000000ff800000,0x00000000ff820000,0x00000000ff880000)
Metaspace used 3505K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 389K, capacity 392K, committed 512K, reserved 1048576K
//结果分析
PSYoungGen(新生代):共1536k,1.5MB
ParOldGen(老年代):共512k,0.5MB
这些相加总内存已经等于2MB了,所以即使永久区(元空间)使用的有内存,但是它逻辑上存在但是物理上不存在 8.2、OOM
OutOfMemoryError:内存不足错误,说明堆内存满了
解决:
使用堆内存调优参数调整堆内存大小,排查是否还会出错
若还会出错,使用JProfiler工具分析内存,排查具体出错位置
8.3、堆内存调优参数
-Xms1m:
设置初始化内存分配大小,默认为内存大小的1/64
-Xmx8m:
设置最大分配内存,默认为内存大小的1/4
-XX:+PrintGCDetails:
打印垃圾回收的详细信息
-XX:+HeapDumpOnOutOfMemoryError
Dump内存文件
-XX:MaxTenuringThreshold(默认15):
设置幸存区里的对象经过多少次GC会进入老年区
......
8.4、使用JProfiler工具分析OOM
首先要设置Dump内存文件
配置:-XX:+HeapDumpOnOutOfMemoryError