JVM 总结
一、(1)类加载器: 负责加载所有的类,为所有被载入内存中的类生成一个java.lang.Class实例对象。一旦一个类被加载如JVM中,同一个类就不会被再次载入了。
(2)类加载器种类 :bootstrapClassloader ExtClassloader、applicationClassloader 、 自定义类加载器
(3)双亲委派机制:
(4)双亲委派机制加载类过程:一个类加载器接收到加载类的请求,他不会立即加载, 而是委托自己的父级类加载器,依次向上委托父级加载器, 如果当前没有父级加载器,开始依次从上往下依次加载,如果父类加载器加载失败,子类加载器尝试加载此类;如果父类加载器加载成功, 则成功返回
(5)双亲委派机制特点:1. 保证该虚拟机 里,类的唯一性。 2. 防止内存出现同样字节码的文件
二、类加载过程: 加载、链接、初始化
加载:是将字节码从不同的数据源加载到jvm虚拟机中;
链接: 包含验证 、准备、解析三步;验证:字节码是否符合jvm 规范,防止恶意字节码, 准备:创建类、接口的静态变量, 并赋初始值,这个初始值,与初始化阶段不同, 这个阶段主要是给他们分配内存; 解析:主要将常量池里面的字符串引用替换成直接引用
初始化:优先进行静态变量的初始化(加载顺序按照代码的顺序依次执行),然后进行类变量的初始化(加载顺序按照代码的顺序依次执行)。如果有父类的话,则先进行父类的加载,同上
三、jvm内存结构
堆:new 的对象,数组,(字符串常量池)线程共享
元空间:class与class加载的元数据信息、静态变量、常量池(运行时常量池、静态常量池) 线程共享
虚拟机栈:局部变量, 栈帧(局部变量表、操作数栈、动态链接、方法返回地址)线程私有
本地方法栈:与虚拟机栈一样,区别这儿执行的都是native修饰的方法 线程私有
统计计数器: 记录线程执行字节码的行号,目的多线程切换的时候, 线程争夺cpu执行权,知道从哪儿开始接续执行 ;线程私有
四.标记垃圾算法:(1)引用计数法,缺点:对象循环引用,无法标记,优点:执行效率高
(2)可达性分析法。gc root 执行链, 根据引用链,可以解决对象循环引用问题。(虚拟机栈、本地方法栈、静态属性、常量引用)
五:垃圾回收算法,各自的优缺点:
(1)标记清除 优点:效率比较高,不会改变对象的引用地址 缺点: 会产生内存碎片
(2)标记整理 优点: 不会产生内存碎片,相比标记清除效率比较低, 缺点:有可能改对象的引用地址
(3)标记复制 优点:不会产生内存碎片, 缺点;需要把内存平均分一块,用空间换时间,
(4)分代算法 优点:分新生代与老年代, 可以降低垃圾回收的范围,减少stop the word 的时间
六、垃圾回收器种类,各自优缺点,以及使用场景
串行:serial 、serial old、(单线程垃圾收集,在多核cpu 下, 这样配置, 优点小才大用,使用一般堆内存在2g以内)
并行:parallel Scavenge、 parallel old、parNew(多线程, 效率比单线程要高, 缺点: 使用cup线程资源)
并发:SMS 、G1(1初始标记:只标识与gc root 直接关联的引用。 2.并行标记:多线程标识直接引用下的引用链,由于与用户线程同时执行,会产生垃圾,3 再次标记:用户线程新产生的垃圾,4清除),sms使用的标记清除算法。会产生内存碎片,会产生浮动垃圾
g1:结构是划分了2048个区域, 每个区域大小(1mb-32mb), 区域分为eden、old、survivor、 H区域(存放大对象),区域与区域之间使用的是标记复制算法, 没有内存碎片。场景一般堆内存大于4g以上,性能比较高
七:jvm 性能优化: 减少垃圾回收频率、减少stw时间
1、设置堆内存最大值与最小值 一样
2、少使用大对象
3、 避免在java代码里面 调用system.gc
4 、根据 项目合理的使用垃圾回收器
8.jvm 常用分析工具以及常用命令:
工具: jconsole/visualvm
top指令:查看当前所有进程的使用情况,CPU占有率,内存使用情况,服务器负载状态等参数。
jps:与linux上的ps类似,用于查看有权访问的虚拟机的进程,可以查看本地运行着几个java程序,并显示他们的进程号。当未指定hostid时,默认查看本机jvm进程。
jinfo:可以输出并修改运行时的java 进程的一些参数。
jstat:可以用来监视jvm内存内的各种堆和非堆的大小及其内存使用量。
jstack:堆栈跟踪工具,一般用于查看某个进程包含线程的情况。
jmap:打印出某个java进程(使用pid)内存内的所有对象的情况。一般用于查看内存占用情况。
jconsole:一个java GUI监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器的jvm进程
排查cpu 飙高流程:
1. top 查看cpu 过高的进程
2. top -H -p pid 查看进程下各个线程的cpu 使用情况
3. printf "%x\n" threadId 将异常线程号转换成16进制
4. 使用jstack pid | grep 16进制异常线程号 -A 90 输出日志