加载——》连接——》初始化
- 加载
1)将类的字节码载入方法区,并创建类的.class对象
2)如果此类的父类没有加载,会加载父类
3)加载是懒惰执行
- 连接
1)验证:检查加载到的字节信息是否符合JVM规范
2)准备:创建类或接口的静态变量,并赋初始值,半初始化状态
3)解析:把常量池中的符号引用转为直接引用,建立连接。符号引用就是一些符号当被使用的时候转为直接引用
- 初始化:
1)执行静态代码块与非final静态变量的赋值
2)初始化时懒惰执行
2、类加载器双亲委派模型JVM中存在三个默认的类加载器:
1)BootstrapClassLoader:ExtClassLoader的父类加载器,默认负责加载%JAVA_HOME%lib下的jar包和class文件
2)ExtClassLoader:AppClassLoader的父类加载器,负责加载%JAVA_HOME%/lib/ext文件夹下的jar包和class类
3)AppClassLoader:自定义类加载器的父类,负责加载classpath下的类文件
JVM在加载一个类时,会调用AppClassLoader的loadClass方法来加载这个类,其中在每次调用loadClass时会调用findLoadedClass()来判断缓存中是否有这个类,没有的话再使用ExtClassLoader 的loadClass方法来加载类,同样ExtClassLoader的loadClass方法中会先使用BootstrapClassLoader来加载类,如果BootstrapClassLoader加载到了就直接成功,如果没有加载到,那么ExtClassLoader就会自己尝试加载该类,如果没有还加载到,那么则会由AppClassLoader来加载这个类。
所以,双亲委派指的是,JVM在加载类时,会委派给Ext和Bootstrap进行加载,如果没有加载到才会由自己加载。经典的一句话:向上委托加载,向下委托查找
3、JVM内存模型 4、JVM中哪些是线程共享区 5、JVM中哪些可以作为gc root什么是gc root,JVM在进行垃圾回收时,需要找到"垃圾"对象,也就是没有被引用的对象,但是直接找"垃圾"对象是比较耗时的,所以反过来,先找"非垃圾"对象,也就是正常对象,java使用的是根可达算法,那么就需要从某些"根"开始去找,根据这些"根"的引用路径找到正常对象,而这些"根"有一个特征,就是它只会引用其他对象,而不会被其他对象引用,例如:栈中的本地变量、方法区中的静态变量、本地方法栈中的变量、正在运行的线程等可以作为gc root。
6、一个对象从加载到JVM,再到GC清除,都经历了什么过程1)用户创建对象,JVM首先需要到方法区去找对象的类型信息,然后再创建对象
2)JVM要实例化一个对象,首先在堆中创建对象 ——》半初始化状态
3)对象会分配在堆内存新生代的eden区,然后经历一次Minor GC,对象如果存活,就会进入S区,在后续的每次GC中,如果对象一直存活,就会在S区来回拷贝,每移动一次,年龄加一
——多大年龄才会移入老年代?4比特,年龄最大15
4)当方法执行结束后,栈中的指针会先移除掉
5)堆中的对象,经过Full GC就会被标记为垃圾,然后被GC回收
7、JAVA中的引用类型有哪几种1)硬引用(撑爆了也不会回收)
2)软引用(空间不够才会回收,特别适合做缓存) SoftReference
3)弱引用(看见就被回收) WeakReference
4)虚引用(虚引用是所有引用中最弱的一种引用,其存在就是为了将关联虚引用的对象在被GC掉之后收到一个通知。(不能通过get方法获得其指向的对象)堆外内存回收旧用到了这个虚引用)PhantomReference
8、ThreadLocal线程私有的,每次取值和赋值都会从自己线程的ThreadLocalMap。
9、进程?线程?1)进程:静态概念,分配资源
2)线程
- 动态概念 共享资源
- 主线程
第一个启动main线程
进程是系统资源分配的基本单元
线程是系统执行任务的基本单元
注意:线程是不是越多越好? 不是,太多的话cpu都会用在线程切换,执行任务的时间就少了
10、哪些部分会出现内存溢出不会出现内存溢出的区域——程序计数器
出现OutOfMemoryError的情况
1)堆内存耗尽—对象越来越多,又一直在使用,不能被垃圾回收
2)方法区内存耗尽—加载的类越来越多,很多框架都会在运行期间动态产生新的类
3)虚拟机栈累计—每个线程最多会占用1M内存,线程个数越来越多,而又长时间运行不销毁时
出现StackOverflowError的区域
虚拟机栈内部—方法调用次数过多
11、方法区与永久代、元空间之间的关系- 方法区是JVM规范中定义的一块内存区域,用来存储类型信息、常量、静态变量,即时编译器编译后的代码缓存等。
- 永久代是Hopspot虚拟机对JVM规范的实现(1.8之前)
- 元空间是Hopspot虚拟机对JVM规范的实现(1.8以后),使用本地内存作为这些信息的存储空间
常量池,是Class文件的一部分,可以看做是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等类型,这部分内容将在类加载后存放到方法区的运行时常量池
运行时常量池,是方法区的一部分,相对于class文件常量池具有动态性。
13、永久代为什么要被元空间替代1)为永久代设置空间大小很难确定,如果动态加载的类过多就会产生OOM。永久代和元空间最大的区别就是:元空间并不在虚拟机中,而是使用本地内存
2)对永久代进行调优很困难
14、StringTable为什么要调整?jdk7将StringTable放到了堆空间中。因为永久代的回收效率很低,在full gc的时候才会出发。而full gc是老年代的空间不足、永久代不足时才会触发。这就导致StringTable回收效率不高。而我们开发中开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足。放到堆中,能及时回收内存。



