一、内存回收
Minor GC、Major GC、Full GC
Jvm回收:回收的内存一般包括(新生代、老年代、方法区)大部分回收的是新生代
HotSpot Vm回收分两大类型
1、部分收集:
新生代收集(Minor GC/young GC):只是新生代(Eden\s0,s1)的垃圾回收
老年代回收(major GC / Old GC ):只是老年代的垃圾回收
混合收集 G1 GC 会用这种方式
2、整堆收集:回收整个java堆和方法区 (Full GC)
3、JVM新生代
HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to)。默认比例为8:1
1)新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中
2)新创建的对象基本存在于Eden取和From区(from和to均为 Survivor区)
3)当GC后,Eden区中大部分对象都被回收,所有存活的对象通过复制算法复制到 to,from中还存活的对象根据年龄决定其去向,年龄达到阈值(可以通过-XX:MaxTenuringThreshold来设置)则移到老年代,否则被移到To区
4)当老年代内存满了后会触发Full GC进行回收
二、性能监控及调优
目的:防止出现OOM、解决OOM、减少Full GC出现的频率
2.1 设置堆内存大小,显示垃圾回收的详细信息
-Xms512M -Xmx512M -XX:+PrintGCDetails
当老年代内存满了后触发一次full GC
2.2、怎样使对象进入老年代
第一种情况是当对象的年龄大小达到一定大小时就会就如老年代,对象的年龄是由对象经历GC的次数决定的,在新生代每次GC之后如果对象没有被回收则年龄加1,通过以下参数来设置最大年龄
-XX:MaxTenuring Threshod=15
第二种情况是大对象,JVM里面有一个参数可以设置对象的大小超过在指定的大小之后,直接晋升为老年代
-XX:PretenureSizeThreshold=80M
2.3堆空间常用参数
查看所有参数的默认初始值:-XX:PrintFlagsInitial 查看所有参数的最终值:-XX:+PrintFlagsFinal 堆初始大小: -Xms 堆最大大小: -Xmx 或 -XX:MaxHeapSize=size 新生代大小: -Xmn 或 (-XX:NewSize=size + -XX:MaxNewSize=size ) 配置新生代与老年代在堆结构的占比:-XX:NewRatio 设置新生代中Eden和s0/s1空间的比列:-XX:SurvivorRatio 设置新生代垃圾的最大年龄:-XX:MaxTenuringThreshould 幸存区比例 -XX:SurvivorRatio=ratio 晋升阈值 -XX:MaxTenuringThreshold=threshold 晋升详情 -XX:+PrintTenuringDistribution 输出详细的GC处理日志: -XX:+PrintGCDetails 打印简要信息:1 :-XX:+PrintGC 2:verbose:gc FullGC 前 MinorGC -XX:+ScavengeBeforeFullGC
当堆空间溢出时在当前项目目录下面生成一个heapdump快照文件:-Xms8m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
2.4内存分配与垃圾回收参数列表
-XX:+PrintGC 输出GC日志 -XX:+P[rintGCDetails 输出GC的详细日志 -XX:+PrintGCTimeStamps 输出GC的时间戳 -XX:+PrintGCDateStamps 输出GC的时间戳 -XX:+PrintHeapAtGC 在GC前后打印出堆的信息 -Xloggc:../logs/gc.log 日志文件的输出路径
2.5性能优化
性能监控、性能分析、性能调优三个方面解决性能问题
常用工具:
1)jps查询正在运行的程序进程
常用参数:
-q 只显示pid,不显示class名称,jar文件名和传递给main 方法的参数
-m 输出传递给main 方法的参数,在嵌入式jvm上可能是null
-l 输出应用程序main class的完整package名 或者 应用程序的jar文件完整路径名
jps -v
2)jstat用于监控虚拟机的各种运行状态
可以显示本地或者远程虚拟机中的类装载、内存、垃圾收集、JIT编译等运行数据
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
<interval> 用于指定统计数据的周期,单位为毫米(就是每隔多长时间统计一次)
-t 显示程序的运行时间
-class 监控加载类的情况
3)Arthas
基础指令:
dashboard--当前系统的实时数据面板
thread --查看当前jvm的线程堆栈信息
jvm--查看当前jvm的信息
sysprop--查看和修改jvm的系统属性
sysenv--查看jvm的环境变量
vmoption--查看和修改jvm里诊断相关的option
getstatic--查看类的静态属性
heapdump--dump java head
三、垃圾回收
3.1垃圾回收相关概念
system().gc或者Runtime().gc()的调用,会触发Full GC,同时对老年代和新生待进行回收,尝试释放被丢弃对象占用的内存
提醒jvm的垃圾回收器执行,但不一定立马执行
3.2 G1垃圾回收器的日志分析
2021-04-13T19:43:44.816+0800: 117950.759: [GC pause (G1 Evacuation Pause) (young), 0.0186948 secs] [Parallel Time: 13.4 ms, GC Workers: 4] [GC Worker Start (ms): Min: 117950761.1, Avg: 117950761.2, Max: 117950761.3, Diff: 0.2] [Ext Root Scanning (ms): Min: 6.4, Avg: 8.1, Max: 12.8, Diff: 6.4, Sum: 32.5] [Update RS (ms): Min: 0.0, Avg: 2.7, Max: 6.0, Diff: 6.0, Sum: 10.7] [Processed Buffers: Min: 0, Avg: 14.5, Max: 29, Diff: 29, Sum: 58] [Scan RS (ms): Min: 0.1, Avg: 0.2, Max: 0.4, Diff: 0.3, Sum: 0.9] [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.1] [Object Copy (ms): Min: 0.0, Avg: 0.9, Max: 1.6, Diff: 1.6, Sum: 3.8] [Termination (ms): Min: 0.0, Avg: 1.1, Max: 2.1, Diff: 2.1, Sum: 4.4] [Termination Attempts: Min: 1, Avg: 19.8, Max: 38, Diff: 37, Sum: 79] [GC Worker Other (ms): Min: 0.0, Avg: 0.1, Max: 0.1, Diff: 0.1, Sum: 0.4] [GC Worker Total (ms): Min: 13.1, Avg: 13.2, Max: 13.3, Diff: 0.2, Sum: 52.7] [GC Worker End (ms): Min: 117950774.3, Avg: 117950774.3, Max: 117950774.4, Diff: 0.0] [Code Root Fixup: 0.0 ms] [Code Root Purge: 0.0 ms] [Clear CT: 0.5 ms] [Other: 4.8 ms] [Choose CSet: 0.0 ms] [Ref Proc: 0.4 ms] [Ref Enq: 0.0 ms] [Redirty Cards: 0.1 ms] [Humongous Register: 1.3 ms] [Humongous Reclaim: 0.0 ms] [Free CSet: 2.1 ms] [Eden: 595.0M(595.0M)->0.0B(595.0M) Survivors: 1024.0K->1024.0K Heap: 918.7M(1024.0M)->323.4M(1024.0M)] [Times: user=0.03 sys=0.03, real=0.02 secs]
2021-04-13T19:43:44.816+0800 :GC事件发生的时间
117950.759:JVM启动后经历的时间
GC pause (G1 Evacuation Pause):这个是收集器把存活对象从一个区域拷贝到另一个区域的阶段。
(young) 说明这是个YoungGC。
[Parallel Time: 13.4 ms, GC Workers: 4]:说明有4个GC线程
[Eden: 595.0M(595.0M)->0.0B(595.0M) Survivors: 1024.0K->1024.0K Heap: 918.7M(1024.0M)->323.4M(1024.0M)] 这一行说的是堆的大小变化。
四、内存相关
4.1内存溢出
内存溢出(OOM):没有空闲内存,并且垃圾收集器也无法提供更多内存
原因:
1)java堆内存设置不够:可以通过参数-Xms(堆初始化大小)、-Xmx(堆最大大小)来设置
2)代码中有大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)
4.2内存泄露
对象不会被程序用到了,但是GC又不能回收的情况
五、对象引用
引用分:强引用(strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)
除强引用外,其他3中均在JAVA.lang.ref包中
java中默认声明的就是强引用
Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收 obj = null; //手动置null
java中强引用的关系只要还存在,垃圾回收就不能回收掉,即使OOM也不会,可以将强引用赋值为null,这样就可以被回收了
软引用
软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象
如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。
弱引用
弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收
在 JDK1.2 之后,用 java.lang.ref.WeakReference 来表示弱引用。
虚引用
虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样
它随时可能会被回收,在 JDK1.2 之后,用 PhantomReference 类来表示