关于JVM的组成与classloader
JVM有什么好处:
一次编写,到处报错
自动内存管理,垃圾回收机制
JVM执行流程:由java源码编译成字节码(class)文件,再由类加载器对class文件进行装载,将其加入到运行时数据区;运行时数据区可以调用native方法、jit优化器、解释器等
java - v x.class //打印堆栈大小,局部变量的数量和方法的参数
javap -v x.class //打印类的元空间信息
JVM组成
1.什么是程序计数器
每个线程都私有一份的,内部保存字节码的行号。用于记录正在执行的字节码指令的地址。
例如A线程在执行到第10行时,时间片被B线程抢走此时A线程会失去执行权,这时程序计数器会记录下当前行号,当执行权再次被分给A时,A会在上一次执行的基础上继续往下执行
2.java中的堆是什么
堆是线程共享的区域,共享对象实例、数组等,当堆没有更多的内存空间分配给实例,无法再拓展时,就会出现OOM问题
堆内有年轻代、老年代两部分:年轻代被化为eden、S0、S1;根据JVM策略,在eden中未被垃圾回收的实例会进入S0或S1;在经历数次回收后仍存在的实例会进入老年代;老年代是保存一些生命周期长的对象
3.虚拟栈又是什么
栈的特点是先进后出。在线程运行时所需要的内存,即虚拟机栈。
虚拟机栈由多个栈帧组成,对应着方法调用所占用的内存;栈帧一般包含了参数、局部变量、返回地址
每个线程只能有一个活动栈帧,即正在执行的方法
4.栈内存分配是越大越好吗?
默认帧栈内存是1MB,栈帧过大会导致线程数变少。
5.方法内的局部变量是线程安全的吗?
如果是在方法内创建并消费,那么局部变量就是安全的。但是如果局部变量由引用获得并逃离了方法的作用范围,那就是不安全的。
6.栈内存溢出情况
栈帧过多,栈帧过大(不常见)
7.堆栈的区别是什么
栈内存主要用于存储局部变量和方法调用;堆内存主要用于存储java对象和数组。堆会垃圾回收,栈不需要
栈内存是线程私有的;堆内存是线程共有的
栈内存报错是stackoverflow;堆内存保存是OOM
8.什么是方法区method area/元空间metaspace
元空间原属于堆的永久代,后单独出来。主要用于存储类的信息、运行时常量池。
在java1.7及之前还有永久代,现在被改为了本地内存中的metaspace,metaspace主要用于存储类信息,静态变量,常量,编译后的代码。
在动态类加载会越来越多的情况下,永久代会出现内存不可控的状态,一旦内存设小极有可能出现OOM问题。因此在java8之后把永久代转移到了本地内存,一定程度上防止了OOM。
但是如果metaspace的内存无法满足分配的请求时,也会报错oom:Metaspace(默认情况下metaspace的大小是没有上限的,我们可以通过vm options设置-XX:MaxMetaspaceSize来指定大小)
9.什么是常量池/运行时常量池
常量池可以看作为一张表,虚拟机指令根据这张表找到要执行的类名、方法名、参数类型、字面量等
当类被加载时,常量池信息就会被放入运行时常量池,并把里面的符号地址转换为真实地址
10.你听过直接内存吗
常规IO会在用户态(java)调用内核态,内核套需要调用java堆缓冲区,而java堆缓冲区又需要调用系统内存的缓冲区,由系统内存缓冲区来读取文件最终返给java
在NIO中,java堆内存和系统内存是公用的,减少了一层不必要的调用,这就是直接内存。
直接内存不由JVM管理,是由系统内存管理的。使用直接内存少了一次缓存的使用,能够提高性能。直接内存分配读写开销大,且不受JVM内存回收管理
类加载器classloader
1.什么是类加载器,有哪些
JVM只能运行二进制文件,类加载器的作用是将字节码加载到JVM中,让java文件运行起来
一般有四个:
启动类加载器(bootstrap classloader)加载java_home/jre/lib目录的库
扩展类加载器(ext classloader)加载java_home/jre/lib/ext目录的类
应用类加载器(app classloader)加载classpath下的类(一般来说就是我们自己写的类)
自定义类加载器,tomcat就是基于j2ee实现的
2.什么是双亲委派模型
加载某一个类,先委托上一级的加载器进行加载,如果上级加载器也有上级,则会继续向上委托,如果该类委托上级没有被加载,子加载器尝试加载该类
使用双亲委派机制,保证类不会重复加载,确保唯一性。同时保证类库API不会被修改
3.类装载的执行过程
加载:查找和导入class文件——根据类的二进制数据流,在metaspace中保存类的数据结构,在堆中开辟空间保存其对应的对象
验证:保证类加载的准确性——对文件进行检查,查看类的文件格式,语法,字节码等相关信息是否错误。同时class文件会在常量池通过字符串记录自己要使用的方法,检查他们是否存在
准备:为类变量分配内存并设置类变量的初始值——(static变量、static修饰的final的引用类型分配空间在此阶段完成,赋值在初始化阶段完成;static修饰的final的基本类型与字符串常量赋值都在此阶段完成)
解析:把类中的符号引用转换为直接引用
初始化:对类的静态变量,静态代码块执行初始化操作——(初始化一个类时,如果父类尚未初始化则优先初始化其父类;同时包含多个静态方法、变量,则应按照从上到下的顺序执行)
使用:JVM开始从入口方法开始执行用户的程序代码
卸载:用户执行完程序后,jvm销毁创建的class对象

浙公网安备 33010602011771号