JVM
2020-11-20 17:42:57 53 举报
AI智能生成
登录查看完整内容
JVM
作者其他创作
大纲/内容
JVM
内存模型
线程私有
虚拟机栈(线程栈)
局部变量表
操作数栈
动态链接
方法出口
-Xss设置越小count值越小,说明一个线程栈里能分配的栈帧就越少,但是对JVM整体来说能开启的线程数会更多
程序计数器
记录指令执行的行号
本地方法栈
native方法
线程共享
年轻代
eden
参数设置:-Xmn
survivor to
survivor from
年老代
old
方法区(元空间)1.8以后为直接内存
‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M
直接内存
逃逸分析
解释模式(Interpreted Mode):只使用解释器(-Xint 强制JVM使用解释模式),执行一行JVM字节码就编译一行为机器码
编译模式(Compiled Mode):只使用编译器(-Xcomp JVM使用编译模式),先将所有JVM字节码一次编译为机器码,然后一次性执行所有机器码
混合模式(Mixed Mode):依然使用解释模式执行代码,但是对于一些 \"热点\" 代码采用编译模式执行,JVM一般采用混合模式执行代码
GC
GC做的哪些事
哪些对象需要回收
什么时候回收
怎么回收
怎样确定对象已经死亡
引用计数法
这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题
可达性分析
这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,找到的对象都标记为非垃圾对象,其余未标记的对象都是垃圾对象
minror GC、young GC
垃圾收集算法
标记清除
效率低,产生内存碎片,可能造成大对象无法存放
复制算法
效率高,不产生内存碎片,但是会导致内存使用空间减少一半
标记整理
标记后不是清理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象。
分代收集算法
其核心思想是根据对象存活的不同生命周期将内存划分为不同的域,一般情况下将GC 堆划分为老生代(Tenured/Old Generation)和新生代(YoungGeneration)
垃圾收集器
Serial
(-XX:+UseSerialGC -XX:+UseSerialOldGC 单线程
Par New
-XX:+UseParNewGC Serial的多线程版本,一般线程数与cpu核数一致,当然也可以用参数(-XX:ParallelGCThreads)指定收集线程数
Parallel Scavenge
serial old
Par Old
CMS
过程:1.初始化标记2.并发标记3.重新标记4.并发清除;是一种以获取最短回收停顿时间为目标的收集器一般情况下使用 Par new 年轻代,CMS年老代 -XX:+UseConcMarkSweepGC(old)
G1
进入老年代
1.大对象直接进入老年代
2.长期存活的对象进去老年代
3.对象在 Survivor 中每熬过一次 MinorGC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。
4.对象的动态年龄判断;),一批对象的总大小大于这块Survivor区域内存大小的50%,那么此时大于等于这批对象年龄最大值的对象,就可以直接进入老年代了
5.minor GC存活下来的对象,survivor区放不下,直接进入老年代
6.老年代空间分配担保机制“-XX:-HandlePromotionFailure”(jdk1.8默认就设置了)的参数是否设置了
调优工具
1.打印操作日志‐XX:+PrintGCDetails ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCDateStamps ‐Xloggc:./gc.log
2.jps -查看进程
3.jmap -histo 进程id >log.txt;打印对象情况num:序号instances:实例数量bytes:占用空间大小class name:类名称,[C is a char[],[S is a short[],[I is a int[],[B is a byte[],[[I is a int[][]
5.jstack 查看线程,死锁
6.jinfo 查看正在运行的Java应用程序的扩展参数
7.stat命令可以查看堆内存各部分的使用量,以及加载类的数量jstat -gc 进程id 2000 100 每隔两秒执行一次,执行100次(最常用的)
JVM类加载
类加载机制
分为五个部分
加载
在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main()方法,new对象等等,在内存中分配一块表这个class类的空间
验证
验证clas文件是否符合JVM规范
准备
给类的静态变量分配内存,并赋予默认值,如:int a=1;此阶段先为a赋值为0
解析
将符号引用替换为直接引用,所谓的静态连接,动态连接是在程序运行时完成的;虚拟机将常量池中的符号引用替换为直接引用的过程
初始化
对类的静态变量初始化为指定的值,执行静态方法;如int a=1;此时将0换为1
类加载器
启动类加载器
负责支撑JVM运行的,位于JRE/lib目录下的核心类库
扩展类加载器
负责加载JVM运行的位于JRE/lib/EXT的扩展目录
应用程序加载器
负责加载ClassPath路径下的类的包,主要加载自己写的类
自定义加载器
负责加载用户自定义的加载器
双亲委派机制
加载过程
1首先查看指定名称的类是否已经加载过,加载过以后直接返回,未加载过则继续
3.如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载。
设计原因:沙箱安全机制,自己写的java.lang.String.class类不会被加载,这样便可以防止核心API库被随意篡改 2.避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性
打破双亲委派机制
tomcat打破双亲委派原因
1.一个web容器可能部署多个应用,而多个应用需要使用同一个第三方类的不通版本,,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。
2.部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机。
3.web容器有自己的类库,不能与应用程序的类库混淆,基于安全考虑,应该让容器的类库和程序的类库隔离开来。
4.web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情, web容器需要支持 jsp 修改后不用重启。
0 条评论
回复 删除
下一页