JVM虚拟机知识点

java -version 显示JDK 版本

Java HotSpot Client:1.5版本之后,热点探测,对加载的class文件做标记,对于频繁使用的class即时编译JIT本地缓存,不再重新进行编译。

Client更多基于桌面级别应用进行优化,处理的代码量较少,程序和JVM交互频率偏低,相比BS结构处理的线程数较少,内存分配空间相比缩小,例如堆内存只分配十几M到几百M,

JVM默认启用Client端,可以修改jvm 的config 修改设置启用server JVM

server端相比Client端分配内存大,因而可能内存浪费,所以之前默认Client端

JVM

1.类加载子系统与方法区:类加载的类信息,常量池,

2.java堆,主要内存工作区域,所有创建对象都存于堆上。

3.直接内存:堆外空间,直接向系统申请内存空间,直接映射到物理内存。主要用于NIO库,执行效率高于访问堆内存。

4.垃圾回收系统:

5.java栈,虚拟机线程都有一个私有的java栈,java栈中保存着帧信息,java栈中保存着局部变量,方法参数,不共享。

6.本地方法栈:和java栈类似,用于本地方法的调用,native method,调用操作系统的API。

7.PC寄存器:每一个线程私有空间。区分本地方法和非本地方法。如果是本地方法,值为undefined,否则指向当前执行的指令。

8.执行引擎:负责执行虚拟机的字节码,会使用JIT优化速度。

堆结构图及分代:

一般分为新生代,老年代,永久代

1.区分生命周期不同的对象

2.避免碎片和内存浪费

新生代:频繁GC

老年代:频率较低

永久代:静态属性,类信息(JVM一般不进行回收),hotspot JVM独有,趋势:有可能取消

新生代: eden(大部分对象创建的空间,频繁gc,一般可以回收70%~95%) from , to(surviver spaces)

eden:surviver0:surviver1 = 8:1:1

除了大对象直接进入老年代,其他都是eden创建,当eden没有足够空间分配,会发起Minor GC,

GC进行是,所有存活的对象会复制到 survivor from,而to区年龄达到15,会移到老年代。GC分代年龄存储在对象的header。没有达到阈值的对象会被复制到to survivor区 。接着清空from区和eden区。from to会每次GC交换。to survivor一轮GC一定是空的。如果不够直接进老年代。

老年代:一定阈值进入老年代

永久代:不进行垃圾回收。需要再次check G1,可能已经去掉了。

垃圾回收算法:

1.引用计数,古老,计数为0时可以回收,无法处理循环引用。

2.复制算法,复制过去后还能进行相应的内存整理,需要两倍的内存空间(以供交替复制)

3.标记清除(mark-sweep)从根节点开始标记被引用的对象,第二阶段遍历整个堆,此算法需要暂停整个应用,且会产生内存碎片,因此需要优化。

4.标记整理 (复制和清除)对清除算法的优化。

垃圾收集器

minor GC = scavenge GC(eden空间不足,新生成对象申请内存空间失败触发,频繁触发,需要效率高的GC算法)

老年代GC = full GC = major GC,一般伴随至少一次minor GC,(可以用system.gc()显示触发,不是立刻启动,优先启动),时间一般较长如果时间超过3-5s,太长。

Hotspot JVM共提供了7个分代回收器。

1.新生代:serial,ParNew,parallel scavenge

2.老年代:CMS = concurrent mark sweep, Serial Old, Parallel Old

3.新老年代:G1 GC = gabage first

A. serial: JDK 1.5 默认的minor GC,只用一条收集线程GC,需要暂停其他工程线程,stop the world, 可以使用-XX:+UseSerialGC 控制

B. parNew:并行,服务器多核时才会高效,缩短了GC时间,未解决stop the world问题,是serail的多线程版本,是老年代CMS的默认minor GC,CMS可以和serail和parNew同时使用,但不可以和parallel同时使用。parNew单核时不如serail,甚至双核时也不可以,只有多核时才可以有效提升。为了解决安全点的时间长短,即用户线程等待时间。

参数控制:-XX:+UseParNewGC  ParNew收集器

-XX:ParallelGCThreads 限制线程数量,一般等于CPU数量

C.parallel scavenge,为了解决CPU吞吐量的问题。

参数可控,占用GC的时间百分比,不会越低越好,越低会导致次数越频繁。

吞吐量:CPU运行用户程序/(CPU运行用户程序时间+GC时间) 缩短GC时间,可以有效提高CPU吞吐量

老年代:

Serial Old:同样是单线程收集器,使用标记-整理算法(新生代中用的是标记-复制)兼容所有的新生代垃圾收集器

parallel Old:同样使用标记整理算法,只能和parallel scvenge

CMS: 实战时可优化点

并行/并发区别:并行:停止CPU运行用户程序时,GC线程可以多线程运行。

并发:包含了用户线程,垃圾收集线程和用户线程可以交替运行。优化的时候可以考虑将老年代的收集器换成CMS,同时将minor GC设为parNew

G1收集器(后续补充)

JDK1.7加入,不是默认收集器,未来趋势

1.空间整合,采用标记整理,无内存空间碎片,分配大对象不会因为无法找到连续空间而提前触发GC

2.可预测停顿,和CMS一样,GC收集器也追求低停顿,更进一步的G1收集器还能建立可预测的停顿时间模型,能明确指定在一个长度为Nms的时间片段内,消耗在GC上的时间不得超过Nms,几乎是实时Java的垃圾收集器特征。

3.可应用于新老年代,将java堆划分为多个相等的独立region,新老年代概念保留,但没有物理隔阂,可以是一部分(可不连续)Region的集合

G1的新生代和parNew类似,当占用一定比例是触发收集,同样会有短暂停顿。

收集步骤:

1.标记阶段,这个阶段是停顿的,并且会触发一次普通的Minor GC

2.Root Region Scanning,程序运行过程会回收survivor区,将存活对象移到老年代,这一过程必须在young GC之前完成。

3.Concurrent Marking,在整个堆内进行并发标记(和用户线程并发执行),此过程可被young GC中断。

此阶段,如发现区域对象中所有对象都是垃圾,则会被立刻回收。同时,会计算每个region的对象活性比例。

4.remark 再标记,会有短暂的STW。用来收集阶段3产生的新垃圾(因为阶段3和用户线程同时进行);

G1采用了比CMS更快的初始快照算法:snapshot-at-the-begining(SATB)。

5.Copy/Clean up, 多线程sweep失活对象,会有STW。G1将回收区域的存活对象拷贝到新region。

清除remember set,并发清空回收区域并把它返回到空闲region链表中。

6.复制/清除过程后,回收region的活性对象已经被集中回收到深蓝色和深绿色region。

JVM优化:

1.自带bin目录下的

A.jps.exe = linux ps命令  

eg: jps -l 显示当前JVM运行线程ID   jps -v 显示JVM线程ID和JVM配置

B.jstat 查看Hotspot VM运行时信息,eg类加载,内存,GC

常用命令 :jstat -gc 线程ID 时间 次数------  查看GC信息 eg:jstat -34323 250 20

jvisualvm: 图形化界面

可以检测目前的堆空间等内存情况,每种类型的占用空间例如字符串等

可安装插件,例如VisualGC,可查看GC情况

jvm参数:

-Xms:初始化堆大小(包含新老年代)

-Xmx:最大堆大小

-XX:NewSize = n 新生代大小

-XX:NewRatio  新生代比例

-XX:SurvivorRatio 相比于eden大小

-xx:MaxPermSize 持久代大小

设置收集器eg:

-xx:+useSerailGc

-xx:+UseParallelGc

-XX:+UseParallelOldGc

-XX:+UseCocurrentMarkSweep

可通过代码查看当前使用的垃圾回收器,

1 public class Solution {
2     public static void main(String[] args) {
3         List<GarbageCollectorMXBean> list = ManagementFactory.getGarbageCollectorMXBeans();
4         for(GarbageCollectorMXBean l:list){
5             System.out.println(l.getName());
6         }
7     }
8 }

结果:本机运行结果:Copy MarkSweepCompact

在runConfig中运行+xx:useG1GC 则打印结果为YONG:G1 OLD:G1

参数设置例子

32位系统,一般堆空间限制在1.5-2g,64位不可超过物理内存

eg:-xmx3550m -xms3550m -xmn2g(年轻代大小) -xss128k(每个线程的堆栈大小,JDK5.0之后是1M,以前是256K,建议不动此设置)

持久代一般 64m

吞吐量优先的并行收集器

一般不太用于BS系统,主要是用于科学计算等

-XX:parallelgc threads = 20(与CPU核数相关,设置高了也无效,此配置仅对 YONG GC有效,老年代仍为串行)

调优策略:

A年轻代大小:

响应时间优先:尽可能设大,减低发生频率,减少到达年老代的对象

吞吐量优先:尽量可能设置,可达到Gb的程度,对响应时间无要求,垃圾收集可并行进行,一般适用于8cpu以上的应用

响应时间优先:年老代使用CMS,大小需小心设置,需考虑并发会话率和持续时间,小则容易导致内存碎片,高频以及stop the world,大则需要较长收集时间

参考:https://www.cnblogs.com/ityouknow/p/5614961.html

猜你喜欢

转载自www.cnblogs.com/lizzyluvcoding/p/10115640.html
今日推荐