1、运行时数据区
程序计数器:线程私有,如果线程在执行的是Java方法,那么PC记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的是Native方法,那么PC的值为undefined。
Java虚拟机栈:线程私有,每个方法执行的同时都会创建一个栈帧,存储方法的局部变量表(基本类型、对象引用)、操作数栈、动态链接、方法出口等信息
本地方法栈:线程私有,
Java堆:线程共享,存储对象实例
方法区:线程共享,存储已被虚拟机加载的类信息、常量、静态变量等数据
2、垃圾收集
2.1 哪些对象需要被回收?
已经死了的对象需要被回收,怎么判断对象以死。
2.1.1 引用计数法
无法解决循环引用
2.1.2 可达性分析法
GC Roots:1.虚拟机栈中引用的对象;
2.方法区中类静态属性引用的对象;
3.方法区中常量引用的对象;
4.本地方法栈中引用的对象。
2.2 如何回收
2.2.1 标记清除
“标记-清除”(Mark-Sweep)算法,如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。之所以说它是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其缺点进行改进而得到的。
它的主要缺点有两个:一个是效率问题,标记和清除过程的效率都不高;另外一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
2.2.2 复制算法
“复制”(Copying)的收集算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
这样使得每次都是对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为原来的一半,持续复制长生存期的对象则导致效率降低。
2.2.3 标记整理算法
复制收集算法在对象存活率较高时就要执行较多的复制操作,效率将会变低。更关键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。
根据老年代的特点,有人提出了另外一种“标记-整理”(Mark-Compact)算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
2.2.4 分代收集算法
GC分代的基本假设:绝大部分对象的生命周期都非常短暂,存活时间短。
“分代收集”(Generational Collection)算法,把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。
3.垃圾收集器
3.1 Serial收集器 串行
3.2 Serial Old 串行
3.3 ParNew 并行,ParNew收集器其实就是Serial收集器的多线程版本
3.4 CMS
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用都集中在互联网站或B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。
从名字(包含“Mark Sweep”)上就可以看出CMS收集器是基于“标记-清除”算法实现的,它的运作过程相对于前面几种收集器来说要更复杂一些,整个过程分为4个步骤,包括:
初始标记(CMS initial mark)
并发标记(CMS concurrent mark)
重新标记(CMS remark)
并发清除(CMS concurrent sweep)
其中初始标记、重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行。老年代收集器(新生代使用ParNew)
优点: 并发收集、低停顿
缺点: 产生大量空间碎片、并发阶段会降低吞吐量
3.5 Parallel Scavenge 收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量。
3.6 Parallel Old 是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
3.7 G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征
4.JVM命令
4.1 jps 显示指定系统内所有的HotSpot虚拟机进程。
-
-l : 输出主类全名或jar路径
-
-q : 只输出LVMID
-
-m : 输出JVM启动时传递给main()的参数
-
-v : 输出JVM启动时显示指定的JVM参数
4.2 jstat 用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
格式 jstat [option] LVMID [interval] [count]
-
[option] : 操作参数
-
LVMID : 本地虚拟机进程ID
-
[interval] : 连续输出的时间间隔
-
[count] : 连续输出的次数
| Option | Displays… |
|---|---|
| class | class loader的行为统计。Statistics on the behavior of the class loader. |
| compiler | HotSpt JIT编译器行为统计。Statistics of the behavior of the HotSpot Just-in-Time compiler. |
| gc | 垃圾回收堆的行为统计。Statistics of the behavior of the garbage collected heap. |
| gccapacity | 各个垃圾回收代容量(young,old,perm)和他们相应的空间统计。Statistics of the capacities of the generations and their corresponding spaces. |
| gcutil | 垃圾回收统计概述。Summary of garbage collection statistics. |
| gccause | 垃圾收集统计概述(同-gcutil),附加最近两次垃圾回收事件的原因。Summary of garbage collection statistics (same as -gcutil), with the cause of the last and |
| gcnew | 新生代行为统计。Statistics of the behavior of the new generation. |
| gcnewcapacity | 新生代与其相应的内存空间的统计。Statistics of the sizes of the new generations and its corresponding spaces. |
| gcold | 年老代和永生代行为统计。Statistics of the behavior of the old and permanent generations. |
| gcoldcapacity | 年老代行为统计。Statistics of the sizes of the old generation. |
| gcpermcapacity | 永生代行为统计。Statistics of the sizes of the permanent generation. |
| printcompilation | HotSpot编译方法统计。HotSpot compilation method statistics. |
4.3 jmap
用于生成heap dump文件,如果不使用这个命令,还阔以使用-XX:+HeapDumpOnOutOfMemoryError参数来让虚拟机出现OOM的时候·自动生成dump文件。 jmap不仅能生成dump文件,还阔以查询finalize执行队列、Java堆和永久代的详细信息,如当前使用率、当前使用的是哪种收集器等。
-
dump : 生成堆转储快照
-
finalizerinfo : 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象
-
heap : 显示Java堆详细信息
-
histo : 显示堆中对象的统计信息
-
permstat : to print permanent generation statistics
-
F : 当-dump没有响应时,强制生成dump快照
4.5 jhat
与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看。在此要注意,一般不会直接在服务器上进行分析,因为jhat是一个耗时并且耗费硬件资源的过程,一般把服务器生成的dump文件复制到本地或其他机器上进行分析。
4.6 jstack
用于生成java虚拟机当前时刻的线程快照。
命令格式 jstack [option] LVMID
option参数
-
-F : 当正常输出请求不被响应时,强制输出线程堆栈
-
-l : 除堆栈外,显示关于锁的附加信息
-
-m : 如果调用到本地方法的话,可以显示C/C++的堆栈
4.7 jinfo 实时查看和调整虚拟机运行参数。
5.调优
5.1 CPU占用率较高
1、top -c 查看最耗cpu的进程
2、top -Hp pid 找出进程中最耗cpu的线程
3、printf "%x\n" 21742 线程id转16进制
4、jstack 进程id| grep 16进制线程id 定位消耗CPU最多的线程代码
5.2 内存占用较高
采用jmap -histo:live pid查看堆内存中对象的数目和大小
5.3 应用卡死
jstack pid 查看线程运行情况,是否存在死锁
5.4 常用参数设置
官方推荐新生代占堆的3/8
幸存代占新生代的1/10
-Xms4:初始时堆内存
-Xmx4:最大堆内存
-Xmn2g:年轻代内存
-Xss1024K:一个线程的堆栈大小(1M)
-XX:ParallelGCThreads=8:并行收集器的线程数
-XX:+UseConcMarkSweepGC:并发标记清除(CMS)收集器
-XX:+UseParNewGC:并行收集
-XX:+UseCMSCompactAtFullCollection://在FULL GC的时候对年老代的压缩
-XX:NewRatio:新生代与老年代比值,例如:4,表示新生代:老年代=1:4(默认1:2),即新生代占整个堆的1/5
-XX:SurvivorRatio=4:设置两个Survivor区和eden的比值,例如:4,表示两个Survivor:eden=2:4(默认1:1:8),即一个Survivor占年轻代的1/6
-XX:MaxTenuringThreshold=10:垃圾最大年龄,默认15
-XX:CMSInitiatingOccupancyFraction=80://使用80%后開始CMS收集
9万+

被折叠的 条评论
为什么被折叠?



