一、如何判断对象可以被回收
引用计数法(循环引用检测不了):

可达性分析法:
Java 虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象
扫描堆中的对象,看是否能够沿着 GC Root对象 为起点的引用链找到该对象,找不到,表示可以回收
二、四种引用
1、强引用
只有所有 GC Roots 对象都不通过【强引用】引用该对象,该对象才能被垃圾回收
2、软引用(SoftReference)
仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次触发垃圾回收,回收软引用对象,可以配合引用队列来释放软引用自身
3、弱引用(WeakReference)
仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象,可以配合引用队列来释放弱引用自身
4、虚引用(PhantomReference)
必须配合引用队列使用,主要配合 ByteBuffer 使用,被引用对象回收时,会将虚引用入队,由 Reference Handler 线程调用虚引用相关方法释放直接内存
5、终结器引用(FinalReference)
无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由 Finalizer 线程通过终结器引用找到被引用对象并调用它的 finalize方法,第二次 GC 时才能回收被引用对象
三、垃圾回收算法
1、标记清除(速度较快)

2、标记整理(速度慢,不会有内存碎片)

3、复制(不会有内存碎片,需要占用双倍内存空间)

四、分代垃圾回收
jvm内存模型:


- 新生代和老年代内存空间默认比例为1:2,可通过-XX:NewRatio=2修改,Eden区和两个Survivor区的内存空间占比默认为:8:1:1,可通过-XX:SurvivorRatio=8修改
- 对象首先分配在伊甸园区域(eden),例外情况:创建的对象所需内存太大,eden区放不下,则直接在老年代创建
-
当Eden区的空间满了以后,此时创建对象便会触发GC(Minor GC),将Eden区中存活的对象放入幸存区,然后清除Eden区
当触发Eden区的GC时,会将Eden区中还存活的对象放入幸存区S0
当Eden区满了再次触发GC时,会将Eden区中存活的对象和幸存者S0中仍然存活的对象放入幸存区S1,然后清除Eden区和S0区
若再一次触发Eden区的GC,则将存活的对象又重新放回幸存区S0,依次循环
存活的对象被放入幸存区一次,年龄就会加1,当对象的年龄到达15(4bit)时,该对象就会被晋升到老年代, - minor gc 会引发 stop the world,暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行
- 当老年代空间不足,会先尝试触发 minor gc,如果之后空间仍不足,那么触发 full gc,STW的时间更长。如果Full GC完成后还是放不下,则出现 OutOfMemoryError: Java heap space。老年代主要采用标记-清除或标记-整理算法回收
Full GC触发的五种情况:
- 调用System类的gc()方法,但这只是告诉JVM应该进行GC,并不代表JVM会立马执行Full GC
- 老年代内存不足
- 方法区内存不足
- Minor GC过后进行老年代的平均大小大于老年代的可用内存
- 由Eden区、From区向To区复制时,对象大小大于To区可用内存,则把该对象晋升到老年代,而老年代也没有足够的内存存放该对象
S0、S1与From区 To区概念:
事实上,S0就是From区,S1就是To区,但由于复制-清除算法的过程,它会将第一次Minor GC后存活的对象放入From区,此时To区是空的;当第二次Minor GC时,垃圾回收器会扫描Eden区和From区,并将还存活的对象放入To区,然后清空Eden和From区,此时From区会和To区做一个交换,这样空的From区就会作为下一次GC的To区继续放置存活的对象,即:复制之后有交换,谁空谁就做To区
相关VM参数:
-XX:+PrintFlagsInitial:查看所有的参数默认值
-XX:+PrintFlagsFinal:查看所有的参数最终值
-Xms:设置初始堆内存
-Xmx:设置最大堆内存
-Xmn:设置新生代的内存
-XX:NewRatio:配置新生代与老年代在堆结构的占比
-XX:SurvivorRatio:配置新生代中Eden区与Survivor区的占比
-XX:MaxTenuringThreshold:设置新生代垃圾的最大年龄
-XX:+PrintGCDetails -verbose:gc:输出GC的详细日志
六、常用JVM调优工具
1、jstat
用法:jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
option可以由以下值构成
类装载相关的:
-class:显示ClassLoader的相关信息:类的装载、装载数量、总空间、类装载所消耗的时间等
垃圾回收相关的:
-gc:显示与GC相关的堆信息。包括Eden区、两个Survivor区、老年代、永久代等的容量、已用空间、GC时间合计等信息
-gccapacity:显示内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
-gcutil:显示内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause:与-gcutil功能一样,但是会额外输出导致最后一次或当前正在发生的GC产生的原因
-gcnew:显示新生代GC状况
-gcnewcapacity:显示内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间
-geold:显示老年代GC状况
JIT相关的:
-compiler:显示JIT编译器编译过的方法、耗时等信息
-printcompilation:输出已经被JIT编译的方法
interval用于指定输出统计数据的周期,单位为毫秒。即:查询间隔
count用于指定查询的总次数
-t可以在输出信息前加上一个Timestamp列,显示程序运行时间。单位:秒
-h可以在周期性数据输出时,输出多少行数据后输出一个表头信息
jstat -class 8496(jvm进程号) 1000 10 --每秒打印一次8496进程号java应用类装载相关信息,一共打印10次
返回结果分别显示类装载个数、类装载字节数,未装载个数....
2、jmap
基本用法
jmap [option] <pid> (to connect to running process)
jmap [option] <executable <core> (to connect to a core file)
jmap [option] [server_id@]<remote server IP or hostname> (to connect to remote debug server)
其中option包括:
| 选项 | 作用 |
| -dump | 生成dump文件 -dump:live只保存堆中的存活对象 |
| -finalizerinfo | 以ClassLoader为统计口径输出永久代的内存状态信息 |
| -heap | 输出整个堆空间的详细信息,包括GC的使用、堆配置信息,以及内存的使用信息 |
| -histo | 输出堆空间中对象的统计信息,包括类、实例数量和合计容量 |
| -F | 当虚拟机进程对-dump选项没有任何响应时,强制生成dump文件 |
-dump 通常在写Heap Dump文件前会触发一次Full GC,所以heap dump文件里保存的都是FullGC后留下的对象信息。生成dump文件是个比较耗时的操作。
手动语法:
jmap -dump:format=b,file=<filename.hprof> <pid> #format=b代表标准格式 jmap -dump:live,format=b,file=<filename.hprof> <pid> #区别:只生成存活对象的dump文件,生产常用此方式,避免文件过大 例: jmap -dump:format=b,file=D:/1.hprof 16164 jmap -dump:format=b,file=D:/2.hprof 16164 jmap -dump:live,format=b,file=D:/3.hprof 16164
自动语法(配置在jvm运行参数里,只在宕机时发生)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=filename
-heap用法:-heap <pid>
-histo用法:-histo <pid>
3、jstack
用于生成虚拟机指定进程当前时刻的线程快照,thread dump中要留意下面几种状态
死锁,Deadlock(重点关注)
等待资源,Waiting on condition(重点关注)
等待资源监视器,Waiting on monitor entry(重点关注)
阻塞,Blocked(重点关注)
执行中,Runnable
暂停,Suspended
常用用法: jstack [-l] <pid> -l:除堆栈外,显示关于锁的附加信息
4、jvisualvm
可视化试图,常用功能:
文件->装入堆dump或线程dump分析,查找n个保留大小最大的对象,下载visual gc插件可查看堆内存gc相关信息,可保存堆dump或线程dump文件并比对分析,cpu和内存采样分析等
dump文件获取可采用jmap命令或通过配置JVM参数生成
选项“-XX:+HeapDumpOnOutOfMemoryError”或“-XX:+HeapDumpBeforeFullGC”
选项“-XX:HeapDumpPath”所代表的含义就是当程序出现OutofMemory时,将会在相应的目录下生成一份dump文件。如果不指定此选项,则在当前目录下生成dump文件