下载分词器jar包
1 | 百度网盘地址: |
使用
1 | 1. 将压缩包解压、重命名为ik_analyzer |
问题
1 | 如果遇到错误:java.lang.AbstractMethodError |
1 | 百度网盘地址: |
1 | 1. 将压缩包解压、重命名为ik_analyzer |
1 | 如果遇到错误:java.lang.AbstractMethodError |
上篇文章简单介绍了七种垃圾回收器、既然G1是最前沿的、有必要补充说明一下:
1. 横跨整个堆内存
: 在G1之前的其它收集器收集范围都是整个新生代或者老年代
G1在使用时、将整个Java堆划分为多个大小相等的独立区域(Region)
保留新生代和老年代的概念、但不再物理隔离、都是一部分Region
(不需要连续)的集合
2. 建立可预测的时间模型
: G1跟踪各个Region里垃圾堆积的价值大小(回收可获得空间大小及回收所需时间的经验值)
在后台维护一个优先级列表, 每次根据允许的收集时间、优先回收价值最大的Region(Garbage First)
这种实验Region划分内存空间及有优先级的区域回收方式、保证了G1在有限时间内的收集效率
3. 避免全堆扫描
: G1将堆分为多个Region、就是化整为零、单Region不可能是孤立的、一个对象分配在某个Region中
可能与整个Java堆任意的对象发生引用关系、在做可达性分析确定对象是否存活时、需要扫整个Java堆保证准确性
严重损耗GC效率,
注意:
为了避免全堆扫描、虚拟机为每个Region维护了一个对应的Remembered Set
、虚拟机发现程序对在Reference
类型的
数据进行写操作时、会产生一个Writer Barrier
暂时中断写操作、检测Reference引用的对象
是否在不同的Region中
(在分代的例子中就是检测老年代对象是否引用了新生代对象)、若是则通过CardTable
把相关引用记录到被引用对象所属的
Region的Remembered Set
中、垃圾回收时,在GC根节点的枚举范围内加入Remembered Set
即可保证不用全堆扫描也能不遗漏
1 | 若不计算维护Remembered Set的操作、G1大致步骤为: |
场景Scense:
1. 多核多CPU而且大内存
2. 要求低停顿
如何实现-XX:MaxGCPauseMillis所设置的目标?
1. 对于新生代来说,G1自动调整新生代的大小
2. 对于老年代来说,每次Mixed Garbage Collecttion的时候回收的Rigion个数会基于
Mixed Garbage Collection的目标次数,每个Region中的存活对象百分比,以及堆全局的垃圾比例来设定
如何实现避免碎片?
无论是新生代还是老年代,使用复制算法(将一批Region复制到另外一批Region中)
如何避免可达性分析扫描整个堆?
每一个Region都有自己的RSets(Remembered Set) 用来记录对自己Region内对象的引用
在什么时机进行Mixed Garbage Collection?
在堆的使用率达到-XX:InitiatingHeapOccupancyPercent所设置的使用率(老年代使用的内存/整个堆内存)时
判断的时机是? 每次Young GC结束的时候
因为老年代空间中的使用内存发生变化只有一个情形:Young GC的时候
G1的哪些过程需要STW?
1) young gc: 采用的是复制算法 - 会STW、多线程进行
2) mixed gc: 也是复制算法、mixed gc也包括对新生代的收集
3) global concurrent mark中的initial mark、remark、部分clean up
既然有CMS,为什么要选择G1?
1. STW更加可控
2. 由于采用了标记-整理算法,不会产生内存碎片
Humongous Objects的分配和回收:
1. 怎么算?大于Region的空间的一半的算Humongous Objects
2. 放哪里?Humongous Objects被分配在Humongous Region,直接在老年代
3. 回收:不在mixed gc,而在 global concurrent marking的最后一步:clean up中
可达性分析:
找一组对象作为GC Root(根结点),并从根结点进行遍历,遍历结束后如果发现某个对象是不可达的,
那么它就会被标记为不可达对象,等待GC
哪些对象可以作为GC Root
能作为GC Root的对象必定为可以存活的对象,
eg. 全局性的引用(静态变量和常量)以及某些方法的局部变量(栈帧中的本地变量表)
以下对象通常可以作为GC Root:
1) 存活的线程
2) 虚拟机栈(栈桢中的本地变量表)中的引用的对象
3) 方法区中的类静态属性以及常量引用的对象
4) 本地方法栈中JNI引用的局部变量以及全局变量
1 | 1. -XX:MaxGCPauseMillis |
1. 跟cms一样、无法避免浮动垃圾的产生和溢出
可以增加堆大小、或者GC线程`-XX:ConcGCThreads`来尽量避免
2. 同样存在晋升失败的问题
可以提升`-XX:G1ReservePercent`同时同比例的增加堆大小、
或者提前启动标记周期(减少-XX:InitiatingHeapOccupancyPercent)
收集器 | 串行、并行or并发 | 新生代/老年代 | 算法 | 目标 | 适用场景 |
---|---|---|---|---|---|
Serial | 串行 | 新生代 | 复制算法 | 响应速度优先 | 单CPU环境下的Client模式 |
Serial Old | 串行 | 老年代 | 标记-整理 | 响应速度优先 | 单CPU环境下的Client模式、CMS的后备预案 |
ParNew | 并行 | 新生代 | 复制算法 | 响应速度优先 | 多CPU环境时在Server模式下与CMS配合 |
Parallel Scavenge | 并行 | 新生代 | 复制算法 | 吞吐量优先 | 在后台运算而不需要太多交互的任务 |
Parallel Old | 并行 | 老年代 | 标记-整理 吞吐量优先 | 在后台运算而不需要太多交互的任务 | |
CMS | 并发 | 老年代 | 标记-清除 | 响应速度优先 | 集中在互联网站或B/S系统服务端上的Java应用 |
G1 | 并发 | both | 标记-整理+复制算法 | 响应速度优先 | 面向服务端应用,将来替换CMS |
1. `可达性`: GC Root可以到达此对象
2. `并行执行`: 多个线程同时执行gc
3. `并发执行`: 用户线程和GC线程同时执行
jps
: JVM Process Status Tool. 显示指定系统内所有HotSpot vm 进程jstat
: JVM statistic Monitor Tool. 用于收集vm各方面的运行数据jinfo
: Configuration Info For Java. 显示虚拟机配置信息jmap
: Memory Map For Java. 生成内存转储快照文件(headdump文件)jhat
: JVM Head Dump Browser. 用于分析dump文件、jstack
: 显示虚拟机的线程快照
jps
usage
: jps [opt] [hostid]
-q
只输出LVMID 省略主类的名称-m
输出虚拟机的进程启动时传递给主类函数的参数-l
输出主类的全名、若主类注销的是jar包、输出jar包路径-v
输出虚拟机启动时的jvm参数
jstat
usage
: jstat [opt vmid [interval][s|ms] [count]]
-class
监视类装载、卸载数量、总空间及类装载所需时间-gc
监视Java堆情况、包括Eden区、两个Survivor区、老年代、永久代的容量、已用空间、GC时间合计等信息-gccapacity
监视内容与-gc
基本相同、主要关注java堆各个区域用到的最大、最小空间-gcutil
监视内容与-gc
基本相同、主要关注已使用空间与总空间的比率-gccause
与-gcutil
相同、会额外输出导致上次gc的原因-gcnew
监视新生代gc的状况-gcnewcapacity
与gcnew
基本相同、输出主要关注最大、最小空间-gcold
监视老年代gc的状况-gcoldcapacity
与gcold
基本相同、输出主要关注最大、最小空间-gcpermcapacity
输出永久代最大、最小空间-compiler
输出jit编译过的方法、耗时等信息-printcompalition
输出已被编译过的方法
1 | eg. jstat -gcutil 41610 250 3 |
jinfo
usage
: jinfo [opt] pid
实时查看和调整虚拟机启动参数
eg. jinfo -flag CMSInitiatingOccupancyFraction 41610
使用[+|-] name
修改一部分运行时虚拟机参数值
也可以使用jps -v
来查看启动时默认参数-XX:+PrintFlagsFinal
可以将参数打印出来
jmap
-dump
生成快照文件
eg. jmap -dump:format=b, file=path pid-finalizerinfo
线上在F-Queue中等等Finalizer线程执行finalize方法的对象-heap
线上Java堆详细信息-histo
显示堆中对象的统计信息-permstat
以classLoader为统计路径、显示永久代内存使用情况-F
虚拟机不响应-dump时、使用-F强制生成dump文件
1 | jmap -histo[:live] pid 显示堆中活跃对象 |
jhat
Usage:
jhat -port 9000 dump-file
-port
指定端口
分析结果以包
为单位、分析内存泄露时、可能会用到 Heap Histogram(与 jmap -histo 功能一致)
stack trace for java
生成虚拟机当前时刻的快照Usage
: jstack opt vmid
-F
正常的输出请求不被响应时、强制输出线程堆栈-l
除堆栈外、显示线程的锁信息-m
若调用本地方法、显示C/C++的线程堆栈
参数名称 | 含义 | 默认值 | 备注 |
---|---|---|---|
-Xms | 初始堆大小 | 物理内存的1/64(<1G) | 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制. |
-Xmx | 最大堆大小 | 物理内存的1/4(<1G) | 默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制 |
-Xmn | 年轻代大小 | 注意 :此处的大小是(eden+ 2 survivor space)与jmap -heap中显示的New gen是不同的。 整个堆大小=年轻代大小 + 年老代大小 + 持久代大小.增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8 |
|
-Xss | 每个线程的堆栈大小 | JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右,一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。(较长)和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:””Xss is translated in a VM flag named ThreadStackSize”一般设置这个值就可以了。 | |
-XX:NewRatio | 年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代) | -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。 | |
-XX:SurvivorRatio | Eden区与Survivor区的大小比值 | 设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10 | |
-XX:MaxTenuringThreshold | 垃圾年龄的最大值 | 如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概率 该参数只有在串行GC时才有效 | |
-XX:PretenureSizeThreshold | 对象超过多大是直接在老年代分配 | 0 | 单位字节 新生代采用Parallel Scavenge GC时无效,另一种直接在老年代分配的情况是大的数组对象,且数组中无外部引用对象. |
-XX:LargePageSizeInBytes | 内存页的大小不可设置过大, 会影响Perm的大小 | =128m | |
-XX:+CollectGen0First | FullGC时是否先YGC | false | |
-XX:+UseFastAccessorMethods | 原始类型的快速优化 | ||
-XX:+UseBiasedLocking | 锁机制的性能改善 | ||
-XX:NewSize | 年轻代大小(JDK 1.3/1.4) | ||
-XX:MaxNewSize | 年轻代最大值(JDK 1.3/1.4) | ||
-XX:PermSize | 设置持久代(perm gen)初始值 | 物理内存的1/64 | |
-XX:MaxPermSize | 设置持久代最大值 | 物理内存的1/4 | |
-XX:ThreadStackSize | Thread Stack Size | (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.] | |
-XX:+AggressiveOpts | 加快编译 |
参数名称 | 含义 | 默认值 | 备注 |
---|---|---|---|
-XX:+UseParallelGC | Full GC采用parallel MSC(此项待验证) | 选择垃圾收集器为并行收集器.此配置仅对年轻代有效.即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集.(此项待验证) | |
-XX:+UseParNewGC | 设置年轻代为并行收集 | 可与CMS收集同时使用, JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值 | |
-XX:ParallelGCThreads | 并行收集器的线程数 | 此值最好配置与处理器数目相等 同样适用于CMS | |
-XX:+UseParallelOldGC | 年老代垃圾收集方式为并行收集(Parallel Compacting) | java6开始出现的参数 | |
-XX:MaxGCPauseMillis | 每次年轻代垃圾回收的最长时间(最大暂停时间) | 如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值. | |
-XX:+UseAdaptiveSizePolicy | 自动选择年轻代区大小和相应的Survivor区比例 | 设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开. | |
-XX:GCTimeRatio | 设置垃圾回收时间占程序运行时间的百分比 | 公式为1/(1+n) | |
-XX:+ScavengeBeforeFullGC | Full GC前调用YGC | true | Do young generation GC prior to a full GC. (Introduced in 1.4.1.) |
参数名称 | 含义 | 默认值 | 备注 |
---|---|---|---|
-XX:+UseConcMarkSweepGC | 使用CMS内存收集 | ||
-XX:CMSFullGCsBeforeCompaction | 多少次后进行内存压缩 | 由于并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生”碎片”,使得运行效率降低.设置运行多少次GC以后对内存空间进行压缩,整理 | |
-XX:+CMSParallelRemarkEnabled | 降低标记停顿 | ||
-XX+UseCMSCompactAtFullCollection | 在FULL GC的时候,对年老代进行压缩 | CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用 | |
-XX:+UseCMSInitiatingOccupancyOnly | 使用手动定义初始化定义开始CMS收集 | 禁止hostspot自行触发CMS GC | |
-XX:CMSInitiatingOccupancyFraction=70 | 使用cms作为垃圾回收使用70%后开始CMS收集 | 92 | 为了保证不出现promotion failed错误、设置需要满足:http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html#CMSInitiatingOccupancyFraction_value |
-XX:CMSInitiatingPermOccupancyFraction | 设置Perm Gen使用到达多少比率时触发 | 92 | |
-XX:+CMSIncrementalMode | 设置为增量模式 | 适用于单CPU的情况 |
参数名称 | 含义 | 默认值 | 备注 |
---|---|---|---|
-XX:+PrintGC | [GC 118250K->113543K(130112K), 0.0094143 secs] | ||
[Full GC 121376K->10414K(130112K), 0.0650971 secs] | |||
-XX:+PrintGCDetails | 输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [ParNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs] | ||
-XX:+PrintGCTimeStamps | 输出每个阶段的gc时间 | ||
-XX:+PrintGCApplicationStoppedTime | 打印垃圾回收期间程序暂停的时间.可与上面混合使用 | 输出形式:Total time for which application threads were stopped: 0.0468229 seconds | |
-XX:+PrintGCApplicationConcurrentTime | 打印每次垃圾回收前,程序未中断的执行时间.可与上面混合使用 | 输出形式:Application time: 0.5291524 seconds | |
-XX:+PrintHeapAtGC | 打印GC前后的详细堆栈信息 | ||
-Xloggc:filename | 把相关日志信息记录到文件以便分析.与上面几个配合使用 | ||
-XX:+PrintTLAB | 查看TLAB空间的使用情况 | ||
-XX:+PrintTenuringDistribution | 查看每次minor GC后新的存活周期的阈值 | Desired survivor size 1048576 bytes, new threshold 7 (max 15) new threshold 7即标识新的存周期的阈值为7 |
Java垃圾回收的依据是:是否还有引用.
jdk1.2 之前的定义是:
若reference类型的数据中存储的数值代表一块内存的起始地址、则这块内存代表一个引用
jdk1.2 之后进行了扩充:
分为
强引用
、软引用
、若引用
、虚引用
.
如何定义 ?强引用 (strong reference)
: 程序代码中普遍存在的、类似 Object obj = new Object()
这类的引用, 只要引用还在、永远不会被回收掉的对象
软引用 (soft reference)
:描述一些还有用、但不是必须的对象. 软引用关联的对象、在系统将要发生OOM
前会对这些对象进行一次回收、若回收能够产生足够的空间、则不会发生OOM
, 回收完成依然没有足够的空间才会抛出OOM
异常, JDK1.2
之后、系统提供了SoftReference
来实现软引用
弱引用 (weak reference)
: 也是非必须对象、比软引用的引用更弱一些、被弱引用关联的对象只能生存到下次gc发生之前、当垃圾收集器工作时、无论当前内存是否足够、都会回收掉只被弱引用关联的对象JDK1.2
之后提供了WeakReference类
来实现弱引用
虚引用 (Phantom reference)
: 一个对象是否有虚引用的存在、完全不影响其生存时间、也无法通过虚引用来取得一个对象的实例、设置虚引用的唯一目的就是能在整个对象进行垃圾收集时收到一个系统通知
看懂了gc日志、可能心中还有小小的疑惑?
在内存的动态分配和回收机制十分成熟的情况下、仍然没办法避免排查各种内存溢出、内存泄露的问题, 当垃圾收集称为系统达到更高并发量的瓶颈时、就需要了解gc的细节、对gc进行必要的监控和调节
程序计数器、虚拟机栈、本地方法栈 随线程运行结束而消亡、这几个区域的内存分配和回收具有确定性、不需要过多的考虑内存回收问题
而Java堆和方法区、则在运行时才知道要创建的对象、内存的分配是动态的、垃圾回收主要关注的是这部分的内存
- 引用计数法
给对象添加一个引用计数器、当有新的引用时、计数器的值+1, 引用失效是、计数器的值-1, 计数器的值为0的对象就是不再有引用的对象
这种方式的判断效率很高、实现也比较简单、但是不太好判断 循环引用的问题
A->B, B->A
- 可达性分析
通过GC Roots
作为分析的起点、从这些节点向下搜索、若一个对象通过任意引用链不可达、则会被判断为可回收对象
1 | 可作为 `gc root` 的对象: |
为了避免分析过程中对象的引用关系还在不断的发生变化、导致分析结果的准确性无法保证
系统停顿下来后如果得知对象引用关系呢 ?
在hotspot的实现中、有一个OopMap的数据结构、在类加载的时候, 它就把对象内什么偏移量位置上是什么类型的数据计算出来、在jit编译的过程中也会在特定的位置记录桟和寄存器哪些位置是引用、这样gc扫描时就可以直接得到了
但是、为什么是特定位置 ?
如果每条指令都生成对应OopMap、会需要大量的额外空间、所以只是在特定位置(安全点safepoint
)记录这些信息notice
: 设置标记等待线程运行到安全点再gc解决了大部分问题、但如果线程是sleep
或者block
状态呢 ?线程无法响应jvm的中断请求、运行到安全点去中断挂起、jvm也不可能得到线程被重新分配CPU时间、so、有了安全区域
-safe region
来解决safe region
: 在一个代码片段之内、引用关系不会发生变化、在这个区域内的任意位置进行gc都是安全的,线程在进入安全区域的时候、会设置自己进入安全区域的标记、jvm在gc时、会忽略这类线程
在线程离开安全区域时会检测系统是否已经完成了gc、ok则可以继续运行、否则需要等待可以离开安全点的信号
- 对象优先在Eden区分配、若Eden区无足够的空间、虚拟机会发起一次Minor GC, 经过一次Minor gc、
age
会+1
、达到指定age(-XX:MaxTenuringThreshold指定
)时、对象会进入老年代- Minor gc时、无法放入
survivor
区的对象、会通过分配担保机制
提前转移到old generation
- 大对象直接进入老年代, 为避免提前触发gc 大于
-XX:PreTenureThreshold
指定值得对象会提前进入直接在老年代分配- 若survivor区 相同年龄的所有对象的大小的总和>survivor区的一半、则 age >= 该age值得对象可以直接进入老年代、无需等到
-XX:MaxTenuringThreshold
指定年龄值
可以看到top
的前半部分是系统统计信息、后半部分是进程信息
第1
行:任务队列信息,等同于uptime
、从左到右依次为:系统当前时间
,系统运行时间
、登录用户数
load avg
是系统平均负载、代表最近1min
、5min
、15min
的平均值
第2
行:进程统计信息总进程数
、 正在运行进程数
、休眠进程数
、停止的进程数
、僵死进程数
第3
行:cpu统计信息 us:用户空间cpu占用率
、sy:内核空间cpu占用率
、ni用户进程空间改变过优先级的进程cpu占用率
、id空闲cpu占用率
、wa等待输入输出的cpu时间百分比
、hi硬中断请求
、si软中断请求
第4
行:内存统计信息 total:物理内存总量
free:空闲内存总量
used:已使用内存总量
内核缓冲使用量
第5
行:交换区使用情况
进程区字段含义:pid
: 进程iduser
: 进程所有者的用户名pr
: 优先级ni
: nice值、负值表示高优先级virt
: 进程使用的虚拟内存总量res
: 进程使用的、未被换出的物理内存大小shr
: 共享内存大小s
: 进程状态%cpu
: 上次更新到现在的cpu时间占用百分比%mem
: 进程使用的物理内存百分比time+
: 进程使用的cpu时间总计,单位:1/100s
command
: 命令名
cpu使用率监控
pidstat -t {pid} 1 3 -u 每隔1s输出1次、共输出3次系统状况
pidstat -t {pid} 1 3 -u -t 同时输出线程使用情况
io监控
pidstat -t {pid} 1 3 -d -t 查看线程io信息
内存使用监控
pidstat -t {pid} 1 3 -m -t 查看线程内存使用
各列含义如下:procs
:r
等待运行的进程数
b
可中断休眠的进程数
memory
: kbswpd
虚拟内存的使用项目free
空闲的内存buff
被用来作为缓存的内存数
swap
si
从磁盘交换到内存的交换页数量、so
从内存交换到磁盘的交换页数量、
io
bi
发送到块设备的块数bo
从块设备接收到的块数
system
in
每秒的中断数包括时钟中断cs
每秒的上下文切换数
cpu
us
用户cpu使用时间sy
系统cpu使用时间id
空闲时间