JVM相关知识
2021-03-31 11:35:32 11 举报
Java虚拟机JVM相关知识
作者其他创作
大纲/内容
方法区
是
面向服务端
survivor0from
boolean、byte、char、short、int、float、reference(引用类型)非静态方法:this,形参,局部变量
字节码文件包含 常量池即静态常量池
JIT编译器 JIT Compiler
Old
分配对象内存
堆
类型信息
JDK8 并行 高吞吐
运行时常量池
Thread2
新生代MinorGC
本地方法接口Native Method Interface
对象头Header
类加载器子系统
栈帧
单线程 串行
FullGC
Parallel Old GC
附加信息
栈帧Stack Frame
JIT代码缓存
.......
YoungGC
类的被动引用(不会触发初始化):1. 子类调用父类的静态变量,不会导致子类初始化,只有直接声明该静态变量的类才会被初始化2. 通过数组定义来引用类,不会触发此类的初始化3. 引用类的final静态常量,不会触发此类的初始化(常量在编译阶段存入调用类的常量池中,本质上没有直接引用到定义常量的类)4. 加载一个类时,其内部类不会同时被加载5.一个类加载,当且仅当其某个静态成员(静态域,构造器,静态方法等)被调用时发生。接口的初始化:接口在初始化时,并不要求其父接口全部完成类初始化,只有在真正使用到父接口的时候(如引用接口中定义的常量)才会初始化。
操作数栈
PC Register for Thread1
元空间 Metaspace
对象存活超过阈值
类型指针
局部变量表Local Variavles
......
类变量:1、在链接阶段的准备过程中,给类变量(static)默认赋值。2、在初始化阶段,给类变量显式赋值(即静态代码块赋值)。
main()的栈帧
链接阶段
本地方法栈Native Method Stack
本地内存
PC Register for Thread3
运行时元数据
String s1 =\"a\"; String s2 = \"b\"; String s3 = \"ab\"String s4 = s1+s2;System.out.println(s3==s4);//flase
垃圾清除阶段:1、标记-清除2、复制 (新生代) 概念:将内存划分为两块同等大小内存,每次只使用一块。当一块内存用完,就将存活对象复制到另外一块上,然后再把已使用过的内存空间一次性清理。 优点:每次对整个半区进行回收,内存分配时不用考虑内存不连续(碎片)的情况。 缺点:空间利用率低;在对象存活率较高时进行较多的复制,效率变低。如果不想浪费50%的空间,需要额外的空间进行担保,以应对100%存活的极端情况。 3、标记-压缩(老年代)让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。优点:得到连续的空间,能够较大的对象缺点:整理内存比较耗时
否
伊甸园区 Eden
PC Register for Thread2
1、常量与常量拼接结果在常量池,原理是编译期优化2、常量池中不会存在相同内容的常量3、只要其中一个是变量,结果就在堆中,原理是StringBuilder4、拼接的结果调用intern()方法,则主动将常量池中还没有的字符串对象放入常量池中,并返回地址。
Car class模板对象
并行
验证Verifiction
老年代
Car的Klass类元信息
执行引擎
老年代MajorGC
加载阶段
-Xms:用来设置堆空间(新生代+老年代)初始内存大小 -X 是jvm的运行参数 ms 是memory start-Xmx :用来设置堆空间(新生代+老年代)最大内存大小 建议 Xms = Xmx-Xss :设置单个线程栈的大小-Xmn: 用来设置新生代的大小-XX:NewRatio=2 设置老年代与新生代的比例-XX:SurvivorRatio=8 设置Eden 与 survior区的比例-XX:MaxTenuringThreshold=15 设置进入老年代的年龄 (0-15) 由markword中4bit存储
对象实例化的过程:①、判断对象对应的类是否加载、链接、初始化,即加载类元信息;②、对象分配内存。如果内存规整,则指针碰撞 ; 如果不规整,则按照内存空闲列表分配;③、处理并发问题。采用CAS失败重试、区域加锁保证更新的原子性;每个线程分配一块TLAB;④、属性的默认初始化(零值初始化);⑤、设置对象头信息(运行时元数据(哈希值,GC分代年龄,锁状态标志等)、类型指针(指向方法区的类信息));⑥、属性的显性初始化、代码块中的初始化、构造器的初始化
放置在s0/s1区域
getClassLoader()
静态变量
父类的实例信息id:1001
运行时数据区
引导类加载器BootStrap
ClassLoader
老年代Old
应用类加载器Appclication
1、类初始化过程(即执行 clinit 方法) 父类的静态代码块、静态变量的显示赋值(按照代码顺序执行) 子类的静态代码块、静态变量的显示赋值(按照代码顺序执行)2、实例的初始化过程(即执行 init方法) 1、super(); 2、非静态变量的显示赋值、非静态代码块(按照代码顺序执行) 3、构造函数
String一定存入常量池方法。String s = \"lin\";String s = new String(\"lin\").intern();
字节码文件.class
操作数栈Operand Stack
我的机器
name:
Machine的Klass类元信息
编译器Interpreter
survivor1to
Car.class
Java虚拟机栈(Java Stack)
堆空间
Survivor放得下?
* 题目: * new String(\"lin\")会创建几个对象 * 两个 * 1、new 关键字在堆空间创建 * 2、字符串常量池对象。字节码指令ldc * * 思考: * String s = new String(\"a\") + new String(\"b\");创建几个对象 * 对象1、new StringBuilder() * 对象2、new String(\"a\"); * 对象3、常量池 \"a\" * 对象4、new String(\"b\") * 对象5、常量池 \"b\" * * 深入剖析:StringBuilder 的 toString() 方法 * 对象6、 new String(\"ab\"); * 强调:toString() 方法的调用,在字符串常量池中没有生成 \"ab\"
new Machine()实例
方法信息
晋升老年代
代码生成器 Code Optimizer
Car2
Eden放得下?
线程共享
垃圾回收器Garbage Collection
分析器Profiler
字符串常量池
ParNew GC
方法区 Method Area
解析Resolution
对齐填充(padding)
类加载、链接、初始化
Parallel Scavenge GC
4种引用:1、强引用如Object obj = new Object() ,只要引用存在,就不会被回收。2、软引用(SoftReference)在内存不够时回收。因此可以用于实现对内存敏感的Cache。3、弱引用(WeakReference) 如:WeakHashMap只能存活到下一次垃圾回收。只要发生GC,弱引用对象一旦被发现,不管系统堆空间是否足够,就会被立即回收。4、虚引用 (PhantomReference)唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
JDK9
方法返回地址
Old放得下?
线程私有
局部变量表
Thread3
锁状态标志
Car3
复制算法
Serial Old GC
哈希值GC分代年龄锁状态标志...
getClass()
运行时数据区(Runtime Data Areas)
Old GC
car
目标代码生成器Target Code Generator
程序计数器
执行引擎 Execute Engine
低延迟 并发 标记-清除JDK9 废弃
内存泄露 概念:对象不会再被程序用到,但是GC又不能回收,这就是内存泄露。举例:1、单例模式。如果持有对外部引用的话,那么这个对象不会被回收,会导致内存泄露。2、一些提供close的资源未关闭导致内存泄露。
new Car()实例
本地方法库
垃圾回收器
本地方法栈
堆 Heap Area
...
Young GC
实例化
String s1 = new String(\"a\");s1.intern(); //调用此方法之前,字符串常量池已经存在 “a”String s2 = \"a\";System.out.println(s1==s2); //jdk6: false jdk7/8 : falseString s3 = new String(\"a\") + new String(\"b\");//s3地址:new String(\"ab\")//执行上一行代码后,字符串常量池不存在“ab”s3.intern(); //在字符串常量池中生成\"ab\"。 //jdk6:创建一个新的对象,也就是新的地址; // jdk7/8: 常量池没有创建\"ab\
主线程的虚拟机栈
标记-压缩算法
类的主动引用(触发类的初始化):1、遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要触发其初始化。生成这4条指令的最常见的Java代码场景是:A、new一个类的对象B、调用类的静态变量(除了final静态变量,已在编译期存入常量池)和静态方法2、使用java.lang.reflect包的方法对类进行反射调用,如果类没有进行过初始化,则需要先触发其初始化。3、当初始化一个类,如果其父类没有被初始化,则先初始化它父类4、当虚拟机启动时候,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类(说白了就是先启动main方法所在的类)5、当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化
类加载器
OOM
初始化Initialization
中间代码生成器Intermediate Code Generator
动态链接Dynamic Linking
Thread1
G1GC
Car1
new Machine()
.class文件字节码文件
java虚拟机栈
栈异常:1、OOM(OutOfMeMoryError):栈大小动态扩展,并且在尝试扩展的时候无法申请到足够的内存。2、SOF(StackOverflowError):请求分配的栈容量超过栈允许的最大容量;
args
双亲委派:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都是应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
本地方法库Native Method Liarbries
新对象申请
域信息
一些附加信息
实例数据
本地方法接口
Serial GC
程序计数器 Program Counter Register
方法返回地址Reruen Address
CMS GC
.java文件
准备Preparation
JVM简略图
扩展类加载器Extension
动态链接
垃圾标记阶段:对象存活判断1、引用计数算法。实现简单,判断垃圾效率高。时间开销大,空间开销大,无法解决循环引用。 2、可达性分析算法(GC Roots) GC Roots包含元素: 1.虚拟机栈(栈帧中的本地变量表)中引用的对象 2.方法区中类静态属性引用的对象 3.方法区中常量引用的对象 4.本地方法栈JNI(Native方法)引用的对象总结:由于Root采用栈方式存放变量和指针,所以如果一个指针,他保存了堆中的对象,但是自己又不存放在堆内存中,那它就是一个Root
JVM中唯一没有OOM的区域作用:因为CPU需要不停地切换各个线程,这个时候切换回来的时候,就得知道接着从哪个位置继续执行。为什么是线程私有?为了准确地记录各个线程正在执行的当前字节码指令位置。
final String s1 =\"a\"; final String s2 = \"b\"; String s3 = \"ab\"String s4 = s1+s2;System.out.println(s3==s4);//true
0 条评论
回复 删除
下一页