JVM
2019-11-18 10:30:11 4 举报
AI智能生成
JVM知识点总结
作者其他创作
大纲/内容
运行时数据区域
线程共享区域
堆
描述
问题
方法区
描述
问题
方法区、永久代、元空间
线程私有区域
程序计数器
描述
问题
虚拟机栈
描述
问题
本地方法栈
描述
问题
直接内存
描述
问题
垃圾回收
对象已死吗
引用计数算法
可达性分析算法
可作为 GC Roots 的对象
虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中 JNI(即一般说的 Native 方法) 引用的对象
回收方法区
废弃的常量
无用的类
该类所有的实例都已经回收,也就是 Java 堆中不存在该类的任何实例
加载该类的 ClassLoader 已经被回收
该类对应的 java.lang.Class 对象没有任何地方呗引用,无法在任何地方通过反射访问该类的方法
重要参数
-verbose:class 跟踪类的加载和卸载
-XX:+TraceClassLoading 跟踪类的加载
-XX:+TraceClassUnloading 跟踪类的卸载
再谈引用
垃圾收集算法
标记-清除算法
顾名思义,算法分为标记、清除两个阶段;首先标记出所有需要回收的对象,在标记完成后在统一回收;
不足
效率不高,标记和清除阶段效率都不高
空间问题,清除之后产生大量内存碎片
复制算法
把空间分成两块,每次只对其中一块进行 GC。当这块内存使用完时,就将还存活的对象复制到另一块上面。
不足:解决前一种方法的不足,但是会造成空间利用率低下
新生代使用的是复制算法
标记-整理算法
不同新生代的复制算法,老年代使用的是标记-整理算法;过程跟标记-清除算法一样,但后续不会直接清除可回收的对象,而是将所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存;
老年代使用
分代收集算法
新生代
老年代
垃圾收集器
gc 垃圾收集器组合
分类
Serial 收集器(串行垃圾收集器)
ParNew 收集器(并行垃圾收集器)
并行:Parallel 指多条垃圾收集线程并行工作,此时用户线程处于等待状态
并发:Concurrent 指用户线程和垃圾回收线程同时执行(不一定是并行,有可能是交叉执行),用户进程在运行,而垃圾回收线程在另一个 CPU 上运行。
Parallel Scavenge 收集器
Serial Old 收集器
Parallel Old 收集器
CMS 收集器
步骤
1、初始标记(CMS initial mark):标记 GC Roots 能直接关联到的对象;会stw
2、并发标记(CMS concurrent mark):进行 GC Roots Tracing
3、重新标记(CMS remark):修正并发标记期间的变动部分;会stw
4、并发清除(CMS concurrent sweep)
不足
对 CPU 资源敏感
无法收集浮动垃圾
-XX:CMSInitiaingOccupancyFraction 默认值为92%
CMS运行期间,内存无法满足程序需要,这样虚拟机将启动后备预案:临时启动Serial Old收集器来重新进行老年代的垃圾收集
标记 —— 清除 算法带来的空间碎片
-XX:CMSFullGCsBeforeCompaction
G1收集器
GC日志分析
内存分配策略
对象优先在 Eden 分配
新生代 GC (Minor GC)
老年代 GC (Major GC / Full GC)
新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ,可以通过参数 –XX:NewRatio 配置
Edem : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定)
大对象直接进入老年代
所谓大对象是指,需要大量连续内存空间的java对象;
-XX:PretenureSizeThreshold 设置令大于这个设置值的对象直接在老年代中分配
长期存活的对象将进入老年代
对象在Eden出生并经过一次Minor GC后任然存活,并且被Survivor容纳,将被移动到Survivor区,对象年龄为1,对象在Survivor区没熬过一次Minor GC,年龄增加1,当它年龄达到一定程度(默认15),将会晋升到老年代
-XX:MaxTenuringThreshold 设置晋升到老年代的阀值
动态对象年龄判定
虚拟机不会永远的要求对象年龄达到阀值才会晋升到老年代,如果Survivor空间中相同年龄所有对象的大小总和大于Survivor空间的一半,年龄大于或等于改年龄的对象就可以直接进入老年代,无需等到阀值
空间分配担保
只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行一次Minor GC ,否则进行Full GC
类的加载
类加载过程
加载
查找并加载类的二进制数据到java虚拟机中
链接
验证
确保被加载的类的正确性
准备
为类的静态变量分配内存,并将其初始化为默认值,但是到达初始化之前类变量都没有初始化为真正的初始值
解析
把类中的符号引用转换为直接引用,就是在类型的常量池中寻找类、接口、字段和方法的符号引用,把这些符号引用替换成直接引用的过程
初始化
为类的静态变量赋予正确的初始值
类加载时机
主动使用
创建类的实例
访问某个类或接口的静态变量 getstatic(助记符),或者对该静态变量赋值 putstatic
调用类的静态方法 invokestatic
反射(Class.forName(“com.test.Test”))
初始化一个类的子类
Java虚拟机启动时被标明启动类的类
JDK1.7开始提供的动态语言支持(了解)
被动使用
除了上面七种情况外,其他使用java类的方式都被看做是对类的被动使用,都不会导致类的初始化
所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用”时才能初始化他们
对于一个final类型的静态变量,如果该变量的值在编译时就可以确定下来,那么这个变量相当于“宏变量”。Java编译器会在编译时直接把这个变量出现的地方替换成它的值,因此即使程序使用该静态变量,也不会导致该类的初始化。反之,如果final类型的静态Field的值不能在编译时确定下来,则必须等到运行时才可以确定该变量的值,如果通过该类来访问它的静态变量,则会导致该类被初始化。
类的生命周期
图
子主题
类加载器
类型
Java虚拟机自带的加载器
根类加载器(Bootstrap)
扩展类加载器(Extension)
系统应用类加载器(System)
用户自定义的类加载器
java.lang.ClassLoader的子类
用户可以定制类的加载方式
类加载器加载Class大致要经过如下8个步骤
1、检测此Class是否载入过,即在缓冲区中是否有此Class,如果有直接进入第8步,否则进入第2步。
2、如果没有父类加载器,则要么Parent是根类加载器,要么本身就是根类加载器,则跳到第4步,如果父类加载器存在,则进入第3步。
3、请求使用父类加载器去载入目标类,如果载入成功则跳至第8步,否则接着执行第5步。
4、请求使用根类加载器去载入目标类,如果载入成功则跳至第8步,否则跳至第7步。
5、当前类加载器尝试寻找Class文件,如果找到则执行第6步,如果找不到则执行第7步。
6、从文件中载入Class,成功后跳至第8步。
7、抛出ClassNotFountException异常。
8、返回对应的java.lang.Class对象。
类加载机制:双亲委派机制
图
说明
好处
可以确保Java和核心库的安全:所有的Java应用都会引用java.lang中的类,也就是说在运行期java.lang中的类会被加载到虚拟机中,如果这个加载过程如果是由自己的类加载器所加载,那么很可能就会在JVM中存在多个版本的java.lang中的类,而且这些类是相互不可见的(命名空间的作用)。借助于双亲委托机制,Java核心类库中的类的加载工作都是由启动根加载器去加载,从而确保了Java应用所使用的的都是同一个版本的Java核心类库,他们之间是相互兼容的;
确保Java核心类库中的类不会被自定义的类所替代;
不同的类加载器可以为相同名称的类(binary name)创建额外的命名空间。相同名称的类可以并存在Java虚拟机中,只需要用不同的类加载器去加载即可。相当于在Java虚拟机内部建立了一个又一个相互隔离的Java类空间。
父亲委托机制的优点是能够提高软件系统的安全性。因此在此机制下,用户自定义的类加载器不可能加载应该由父类加载器加载的可靠类,从而防止不可靠甚至恶意的代码代替由父类加载器加载的可靠代码。例如,java.lang.Object类是由跟类加载器加载,其他任何用哪个户自定义的类加载器都不可能加载含有恶意代码的java.lang.Object类。
数组类加载过程
解析ClassLoader
虚拟机参数
-XX:+TraceClassLoading
对象创建
过程
类加载
内存分配
指针碰撞
空闲列表
选择哪种方式:取决于内存是否规整,内存是否规整取决于这块区域选用哪种垃圾收集算法
问题:
设置初始值0
填充对象头
执行 init 方法
高并发情况下分配内存问题
一:对创建对象动作行为进行同步处理,这种同步处理实质是CAS配上失败重试的方式实现保证更新操作的原子性的。
二:把每一个创建对象的动作行为按照线程划分为不同的空间中进行,这种方式就是将创建对象行为放入到线程中,为每一个线程分配一小块内存空间(TLAB),每个线程要分配内存就在自己的TLAB上运行分配,只有当TLAB满了,需要重新分配TLAB时,才需要进行同步锁定。TLAB方式的开启需要通过-XX:+/-UseTLAB参数设定
对象的内存布局
对象头(Header)
实例数据(Instance Data)
对齐填充(Padding)
对象的访问定位
通过句柄访问
图
使用直接指针访问
图
比较
四大引用
分类
强引用(Strong Reference)
软引用(Soft Reference)
弱引用(Weak Reference)
虚引用(Phantom Reference)
如果使用软引用
jvm调优
JVM的参数类型
标配参数
-version
-help
X 参数(了解)
-Xint:解释执行
-Xcomp:第一次使用就编译成本地代码
-Xmixed:混合模式
XX 参数
Boolean 类型:-XX:+ 或者 - 某个属性值(+ 表示开启,- 表示关闭)
KV 设置类型:-XX:key=value
jinfo -flag
参看默认参数
查看JVM初始默认值:-XX:+PrintFlagsInitial
查看修改更新:-XX:+PrintFlagsFinal
打印命令行参数(可以看默认垃圾回收器):-XX:+PrintCommandLineFlags
基本参数
-Xms
-Xmx
-Xss
-Xmn
-XX:MetaspaceSize
-XX:+PrintGCDetails
-XX:SurvivorRatio
-XX:NewRatio
-XX:MaxTenuringThreshold
0 条评论
下一页