最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

JVM垃圾回收与异常处理

XAMPP相关 admin 19浏览 0评论

JVM (java虚拟机)

JVM

JVM:java虚拟机,执行JAVA字节码的虚拟计算机。

是否遇到过这些问题?

- 运行着的线上系统突然卡死,系统无法访问,甚至直接OOM
- JVM GC问题
- JVM参数

所有java程序都运行在JVM上

JVM特点

  • 代码一次编译,到处运行(字节码)
  • 自动内存管理
  • 自动垃圾回收功能
  • 一个JAVA程序进程对应一个JVM
  • JVM允许一个应用有多个线程并行的执行

JVM的整体结构

dqz75

堆 heap

对进程独立,对线程为共享

栈存放对象、指针,而堆空间存放实例

  • 对象、指针 指向堆中存放的实例。
  • 对象出栈时,堆中对应的内容不会回收;而是新的实例进入堆且堆放不下时,发生GC时,才进行回收。
  • GC的本质是:回收已经出栈了的对象或指针的实例。

基于分代收集理论设计,堆空间分为:

逻辑上分为:新生区+养老区+元空间(方法区)

实际上的堆(heap)分为:新生区+养老区

新生区具体细分为:

Eden + Survivor1 或 Survivor2 (Survivor1与Survivor2只有一个存放信息)

Eden + from 或 to

各区域的默认比例与设置参数

默认情况下:

新生区 :养老区 = 1/3:2/3

Eden :S1 :S2 = 8/10:1/10:1/10

堆空间大小的设置

这里实际上指 新生区 + 养老区

-Xms:用于表示堆区的起始内存 (-X:是jvm的运行参数;ms:是memory start)

-Xmx:用于表示堆区的最大内存 (mx:是memory maximum)

  • 堆空间,默认单位为kb,但后面可以接k、m、G作为单位,如:-Xms 6144k;-Xms 6m;
  • 不设置堆空间大小时,默认初始内存大小为:主机内存/64,最大内存大小为:主机内存/4
  • 开发中建议将-Xms与-Xmx设置为一样,原因为:-Xms与-Xmx不一致时,内存不足时会进行扩容,内存充裕时会进行缩容,造成系统资源的不必要损耗。
  • 一旦堆区中的内存大小超过 ‘-Xmx’,将会抛出OOM(outofmemory)

查看堆使用率

(一)方法一
# 获取pid
jps
jstat -gc pid

(二)方法二
# 添加参数
-XX:+PrintGCtails

实例分配的过程与回收过程

dqz075

(1)新对象申请
(2)Eden判断是否放得下
    Eden放得下,将新对象分配到Eden
    Eden放不下,发生一次YGC,YGC后再进行判断Eden是否放得下
        Eden放得下,将新对象分配到Eden
        超大对象,Eden放不下,判断Old是否放得下
            Old放得下,将新对象分配到Old
            Old放不下,发生一次FGC,FGC后再进行判断Old是否放得下
                Old放得下,将对象分配到Old
                Old放不下,发生outofmemory(OOM)

YGC的动作:
(1)YGC时,回收Eden与Servivor中没有对象的实例
    剩余的实例存放到空的S0/S1中,这种情况是S0/S1空间足够
        这个时候会判断对象是否age>阈值(默认15),是则直接放到养老区
    S0/S1空间不足时,将实例放到养老区

FGC的动作:
(1)YGC时,回收Old中没有对象的实例

## 特别需要注意的:
(1)发生GC时,会导致用户线程(作业线程)暂停。
(2)实例每在新生区移动一次,age+1

MinorGC、MajorGC、FullGC的区别

GC按照回收区域分为两大种类型:

(1)部分收集(Partial GC)

(2)整堆收集(Full GC)

  • MinorGC == Young GC,新生区收集,只针对Eden、S0、S1
  • MajorGC == Old GC,养生区收集,只针对Old
  • Full GC,整堆收集,收集整个java堆和方法区的垃圾收集

新生区GC触发机制与特性

  • 触发机制:Eden空间不足,触发YGC
  • Minor GC触发很频繁,回收速度也较快
  • GC会引发STW,暂停用户线程(作业线程),等垃圾回收结束,用户线程才恢复运行

养生区触发机制与特性

特别的:目前,只有CMS收集器会有单独收集老年代的行为。其他收集器均无此行为。

  • 触发机制:Old空间不足,触发MajorGC(Old GC)

 

 

Full GC触发机制与特性

对整堆(新生代,养生代)和方法区的垃圾收集。

触发机制:

  • 调用system.gc(),系统建议执行Full GC,但是不一定会执行;
  • 养生代空间不足;
  • 方法区空间不足;
  • 通过Minor GC后进入养生代的实例大于养生代的可用内存
  • S0/S1复制时,Survivor区空间不足,将实例转存到养生代,但实例大于养生代的可用内存

 

总结

  • Minor GC是清理新生代,但Survivor区满时不会触发;
  • Major GC是清理养生代;
  • Full GC是清理整个堆和方法区,包括新生代,养生代,方法区。

JAVA堆分代思想

  • 分代的唯一理由就是优化GC性能。
  • 若不进行分代,则每次GC都需要堆所有区域进行扫描。

 

内存分配策略

  • 优先分配到Eden
  • 大对象直接分配到养生区
  • 长期存活的对象分配到养生区

TLAB (给每个线程单独分配的缓冲区,私有)

thread local allocation buffer

优势:提高对象的创建效率

 

为什么有TLAB

  • 堆区是线程共享区域,任何线程都可以访问到堆区中的共享数据
  • 由于对象实例的创建在JVM中非常频繁,因此在并发环境下从堆区中划分内存空间是线程不安全的
  • 为避免多个线程操作同一地址,需要使用加锁等机制,进而影响分配速度。
  • 所以进入TLAB机制!!!

 

什么是TLAB

  • 对Eden区域继续进行划分,JVM为每个线程分配了一个私有缓存区域
  • 一旦对象在TLAB空间分配内存失败时(实例过大,或TLAB写满等),JVM就会尝试通过使用加锁机制确保数据操作的原子性,从而直接在Eden空间中分配内存
  • TLAB默认开启
  • 默认下TLAB空间非常小,仅占整个Eden空间的1%

参数:

# TLAB的开与关
-XX:+UseTLAB
-XX:-UseTLAB

# 设置TLAB空间所占用Eden空间的百分比大小
-XX:TLABWasteTargetPercent=1

堆空间的参数设置

-Xms10m
设置堆最小值为10M

-Xmx10m
设置堆最大值为10M

-XX:SurvivorRatio=8
年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:8,表示Eden:Survivor=8:1,一个Survivor区占整个年轻代的1/10

-XX:NewRatio=3
设置年轻代(EC+S0C+S1C)和年老代(OC)的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4(jdk1.8,默认2)

-XX:+PrintGCDetails
打印GC的具体信息

-XX:loggc:D:/a.log
将jvm的日志存储到指定文件

#参考链接

https://www.jianshu.com/p/bcdae3c80c1d

相关命令

jps命令

java提供的一个显示当前所有java进程pid的命令

参数:

-q:只显示pid
-m:输出传递给main方法的参数
-l:输出应用程序main class的完整package名或者应用程序的jar文件完整路径名
-v:显示JVM参数

 

jstat命令

图片

 

# 垃圾回收统计
jstat -gc pid 250 20:查询进程xxx的垃圾收集情况,每250毫秒查询一次,一个查询20次。

S0C:第一个幸存区的大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间

jstat -gcutil pid 250 20:查询GC总体使用情况(百分比)

jstat -gccause pid:额外输出上次GC原因
特别的:
    Allocation Failure:
    表明本次引起GC的原因是因为在年轻代中没有足够的空间能够存储新的数据了。

jinfo命令(jdk8后官方抛弃)

可以用来查看正在运行的java应用程序的扩张参数,包括java system属性和JVM命令行参数,也可以动态的修改正在运行的JVM的一些参数。

用法 说明 举例
jinfo pid 输出当前JVM进程的全部参数和系统属性 jinfo 11772
jinfo -flag name pid 输出对应名称的参数 jinfo -flag PrintGC 11772
jinfo -flag [+|-]name pid 开启或者关闭对应名称的参数(动态修改参数) jinfo -flag -PrintGC 11772
jinfo -flag name=value pid 修改指定参数的值(动态修改参数) jinfo -flag HeapDumpPath=C:\error.hprof 11772
jinfo -flags pid 输出全部的参数 jinfo -flags 11772
jinfo -sysprops pid 输出当前JVM进程的全部系统属性 jinfo -sysprops 11772

 

 

jstack

生成当前时刻的线程快照

  • jstack pid:查看线程情况

 

jmap

将内存使用的详细情况输出到文件

  • jmap -dump:format=b,file=heapDump pid:输出到文件heapDump

jhat

Jhat分析Jmap打印出的堆快照信息

  • jhat 文件名:启动了一个http服务,端口默认是7000,可以使用http://127.0.01:7000/进行访问。信息比较大,得对具体代码有针对的分析,分析哪些对象无法回收的情况

常见问题定位过程

频繁GC或内存溢出

  • jps:查看pid
  • jstat -gc pid 250 20:查看gc情况
  • jstat -gccause pid:查看上次gc原因
  • jmap -dump:format=b,file=heapDump pid:生成堆转储文件
  • 使用jhat分析堆情况
  • 结合代码解决内存溢出或泄漏问题。

 

死锁问题

  • jps:查看pid
  • top -H -p pid:查看哪个线程CPU使用率高
  • printf %x 线程id:获取十六进制线程id
  • jstack pid|grep 十六进制线程id:查看线程情况

转载请注明:XAMPP中文组官网 » JVM垃圾回收与异常处理