java面试资料—JVM相关

来源:互联网 发布:libjpeg.so.62 ubuntu 编辑:程序博客网 时间:2024/05/18 01:48

(1)类的实例化过程

①首先会执行类中static代码块(不管代码块是否在类的开头还是末尾处),如果这个类有父类,同样会优先查找父类中的static代码块,然后是当前类的static。
②然后会从父类的第一行开始执行,直至代码末尾处,中间不管是有赋值还是method调用,都会按顺序一一执行(method),普通代码块{ }...

代码执行完了(包括变量的声明)才开始构造,首先是父类的构造函数,执行带参数或不带参数的构造函数,依赖于实例化的类的构造函数有没有super父类的带参或不带参的构造函数,没有super会默认在第一行调用父类无参构造函数。

④然后会从子类(当前类)的第一行开始执行,直至代码末尾处,中间不管是有赋值还是method调用,都会按顺序一一执行(method),普通代码块{ }...

⑤其次会是子类(当前类)的构造函数,按顺序执行。

⑥最后是类方法的调用执行,如果子类覆盖了父类的method,执行时会先执行子类覆盖的method,method内如果有super.method(),才会调用父类的同名method,否则不会。


(2)jvm的内存分代

虚拟机的堆内存共划分为三个代:年轻代(Young Generation)年老代(Old Generation)持久代(PermanentGeneration)
其中持久代主要存放的是Java类的类信息,与垃圾收集器要收集的Java对象关系不大。所以,年轻代和年老代的划分才是对垃圾收集影响比较大的。


年轻代 
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor区(一般而言,可以自己配置)。
大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当一个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当另一个Survivor区也满了的时候,从前一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。
需要注意,两个Survivor区是对称的,没先后关系,所以同一个Survivor区中可能同时存在从Eden区复制过来对象,和从另一个 Survivor区复制过来的对象;而复制到年老区的只有从前一个Survivor区(相对的)过来的对象。而且,Survivor区总有一个是空的。特殊的情况下,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。

年老代 
在年轻代中经历了N(可配置)次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

持久代(方法区中) 
用于存放静态数据,如 Java Class, Method 等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些Class,例如 Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中动态增加的类型。持久代大小通过 -XX:MaxPermSize= 进行设置。

(3)jvm垃圾回收

什么时间?

1.调用system.gc()主动请求

2.首先将对象放入Eden区,如果空间不足就向其中的一个survivor区上放,如果仍然放不下就会引发一次发生在新生代的minor GC(将存活的对象放入另一个survivor区中,然后清空Eden和之前的那个survivor区的内存);

在某次GC过程中,如果发现仍然又放不下的对象,就将这些对象放入老年代内存里去。大对象以及长期存活的对象直接进入老年区

当每次执行minor GC的时候应该对要晋升到老年代的对象进行分析,如果这些马上要到老年区的老年对象的大小超过了老年区的剩余大小,那么执行一次Full GC以尽可能地获得老年区的空间。

ps:gc与非gc时间耗时超过了GCTimeRatio的限制引发OOM(out of memory),调优诸如通过NewRatio控制新生代老年代比例,通过MaxTenuringThreshold控制进入老年前生存次数


对什么对象?

1.引用计数;每个对象都有一个引用计数器,当引用为0时,进行清理。但是这种方式有弊端,循环引用时无法正确执行清理。

2.根搜索(gc root);从堆栈和静态存储区开始进行遍历所有引用。

GC Roots都有哪些: 
虚拟机栈中的引用的对象 ;
方法区中静态属性引用的对象,常量引用的对象;
本地方法栈中JNI(即一般说的Native方法)引用的对象;

jvm方式:先从根开始搜索,没有被搜索到,而且经过第一次标记-清扫没有复活的对象会被垃圾回收。

复活的情况

在垃圾回收的时候当检测到对象没有用了,需要被回收的时候并不会马上被回收,而是将其放入到一个准备回收的队列,去执行finalize方法。然后等到下次内存回收的时候要是他还是没有被任何人引用的话,就将其给回收了。(如果在finalize方法中重新给对象加个引用,这样对象是有可能不会被回收的)不过finalize方法不推荐使用,他跟C++中的析构函数不同,我们既不能确定什么时候他回被回收,也不能保证这个方法一定会被执行。


执行什么操作?

新生代:复制-清理,survivor之间的复制(还可以使堆内存变得更为紧凑);

老年代:标记-清理(少量垃圾的自适应方式);从堆栈和静态存储区开始,遍历所有引用,找到一个存活对象就设置一个标记,标记工作完成之后,进行清理。

     标记-整理:在标记清除之后,会进行整理,使内存空间更加紧凑。


(4)类加载

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。


加载,查找并加载类的二进制数据,在Java堆中也创建一个java.lang.Class类的对象
连接,连接又包含三块内容:验证、准备、初始化。1)验证,文件格式、元数据、字节码、符号引用验证;2)准备,为类的静态变量分配内存(方法区),并将其初始化为默认值;3)解析,把类中的符号引用转换为直接引用
初始化,为类的静态变量赋予正确的初始值
使用
,new出对象程序中使用
卸载,执行垃圾回收


(5)jvm内存模型

JAVA8中,方法区中的持久代被彻底删除,被元空间取代



原创粉丝点击