JMM
java memory model JAVA内存模型
jmm规定了 jvm和计算机内存是如何协同工作的
一个线程如何看到其他线程修改后的值,以及如何同步共享变量。围绕可见性,有序性,原子性展开。
内存交互操作:对于主内存和工作内存进行交互,定义8种操作来完成
lock unlock read load use assign store write
1.描述一下jvm内存模型,以及哪些空间存放什么内容?
类装载子系统, 运行时数据区, 字节码执行引擎
类装载子系统 负责将字节码加载到jvm中,具体是加载到运行时数据区方法区中
运行时数据区 分为 堆 栈 方法区 本地方法栈, 程序计算器等组成、 主要用于存储程序运行中生成的对象。
字节码执行引擎 包括解释器,即时编译器 ,垃圾回收器。主要执行字节码,并进行垃圾回收
JVM运行时数据区各个区域的作用
堆 里存放new产生的对象。年轻代和老年代。 一般3:7。 年轻代又分为 Eden(8),S1(1),S2(2)。Eden满会触发Minor GC,存活的对象进入S1(S2)区,进行一次GC年龄加1,达到15,对象还存活,进入老年代。老年代中大多存放的是:缓存对象,spring容器对象,静态变量等。老年代满,会触发full GC,回收整个堆,方法区。如果满,导致OOM。 特别是full GC,会触发STW机制(STOP THE WORLD),导致程序短暂卡顿,避免full GC频繁使用。
栈 比如一个程序main线程,test方法线程,每个线程中都包含 局部变量表,操作数栈,动态链接,方法出口。
方法区 类加载器,常量,静态变量
本地方法栈 java执行本地方法服务,c++实现(跨语言调用)。例如:new Thread().start();
程序计数器 程序执行字节码的行号指示器。(每个线程程序执行到哪行啦)。
一个方法对应一块栈帧内存空间。
对于单个线程,栈,本地方法栈,程序计数器都是独有的。生成一个线程都会分别生成一个。堆和方法区是共有的。
堆内存划分空间,如何回收,有哪些算法?
JVM调优
1.为什么需要调优
避免导致oom,
减少频繁的full GC, 会导致stw,导致程序性能下降和响应时间延长
oom 也要区分不同情况,上线时导致,还是上线后运行导致。
2.调优依据
运行日志,异常堆栈,GC日志,快照,dump文件等
3.调优方向
1.合理编写代码,大多数都是代码导致的
2.充分合理的应用cpu资源
3.合理jvm调优参数
3类 标准指令 -开头 这些是所有hotspot都支持,可以用 java -help打印
非标准指令 -X开头, 这些指令和特定hotspot版本对应, 可以用 java -X 打印
不稳定参数 -XX开头, 这些指令和特定hotspot版本对应,并且变化非常大,详细文档资料非常少。在jdk1.8下,有几个常用的不稳定参数 java -XX:+printCommandLineFlags
4.调优步骤
性能监控
GC频繁 cpu突然飙升 OOM 内存泄露 死锁 程序响应时间过长
性能分析
打印GC日志 JPS JSTAT JMAP JINFO jconsole工具
性能调优
适当加一些内存
选择合适的垃圾收集器
优化代码,控制内存使用
加机器优化单节点压力
合理参数
中间件(缓存,消息队列)
性能调优的评估
响应时间 网站 几秒
查数据库 有索引 十几毫秒
如何解决线上GC频繁问题?
1.查看监控,了解出现问题的时间点和FGC的频率(对比正常情况看频率是否正常)
2.了解该时间点是否有程序上线以及基础组件升级
3.了解jvm参数配置,包括,堆空间各个区域大小,新生代和老年代分别采用哪种垃圾收集器,分析是否合理
4.再针对步骤1中列出的可能原因进行排查,其中元空间打满,内存泄漏,代码显示调用gc方法比较容易排查
5.针对大对象或者长生命周期对象导致的FGC,可通过 jmap -histo命令,结合dump堆内存文件进一步分析,需要定位到可疑对象
6.可疑对象定位到具体代码再次分析,这个时候要结合GC原理和jvm参数配置。弄清楚可疑对象是否满足进入老年代的条件再下结论
如何快速定位线上OOM问题
请求进来,去堆里面申请空间,如果此时内存满了,就会触发full GC 如果full gc后,内存仍然满,就会导致 outofmeoryerror异常
,oom应用会挂掉吗,不一定,如果某些请求不申请堆内存的空间,依然可以正常运行,如果并发非常高,需要申请内存空间,这个时候我们的应用进程会彪高,进而操作系统将进程杀掉,应用从而挂掉,会有风险。
#原因
1.一次性申请的太多 更改申请对象数量
2. 内存资源耗尽没有释放 即使释放 (线程,数据库链接 ,引入池化思想 )
3. 本身资源不够 jmap -heap + 进程号 查看堆信息
1和2找到对应代码,对应资源释放
系统已经oom挂掉了 提前设置 -XX:----------------导出dump文件到指定目录 找出代码位置 。 用 java jvjm 或 arthas
jmap -histo
系统运行还未oom 导出dump文件 会导致stw,但是不导,会成倍时间去解决
描述一下类初始化过程
具体参照: jdk源码解析jvm类加载机制
加载(.classs)----验证----准备----解析-----初始化----使用-----卸载
(1)加载:查找和导入Class文件; (2)校验:检查载入Class文件数据的正确性;
(3)准备:给类的静态变量分配存储空间; (4)解析:将符号引用转成直接引用;
(5)初始化:对类的静态变量,静态代码块执行初始化操作 (6)使用:调用方法属性等操作
(7)卸载:不使用
类实例化顺序
没有父子/继承关系
静态代码块 > 非静态代码块 > 构造函数
父子/继承关系
父类 静态代码块 > 子类 静态代码块 > 父类 非静态代码块 > 父类 构造函数 >子类 非静态代码块 > 子类 构造函数
类加载器中双亲委派模型 启动类加载器 扩展程序类加载器 应用程序类加载器
优点:沙箱保护机制以及避免类的重复加载
可以通过代码打破双亲委派模型,只需要自己写的类 extends classLoder 重写loadclass 方法
JVM有哪些垃圾收集器,实际中如何选择
新生代 复制
老年代 标记清除算法
OOM和sof
OOM
java堆溢出:一般由于内存泄漏或者 堆设置大小不当引起的,可以通过设置参数 -xms -xmx 设置堆的大小
方法区溢出:包括运行时常量池溢出,一般由于大量生成的class导致,可以通过 -xx.permsize 和 -xx.maxpermsize 来设置区的大小
SOF
java虚拟机栈和本地方法栈内存溢出:一般由于程序中出现死循环或者深度递归调用造成,栈设置太小也会出现此现象,通过参数-xss设置栈的大小
简述一下内存溢出的原因,如何排查线上问题?
JAVA程序导致cpu飙升
添加链接描述
JVM调优工具
添加链接描述