java虚拟机知识
1.jvm组成部分:
程序计数器:占用很小的内存空间,保存线程执行字节码的行号。如果执行的是Java方法,计数器指向字节码的地址,如果是 native方法,计数器的值为空,每个线程都有一个自己的程序计数器;这个内存区域是java虚拟机中唯一没有规定内存溢出异常的区域。
虚拟机栈:是线程私有的,生命周期和线程一样;是java方法执行的内存模型,java方法的调用到结束,就对应着一个栈帧在虚拟机中的入栈和出栈。局部变量表需要的内存空间在在编译期间分配,进入一个方法时,方法需要的局部变量空间是确定的;
本地方法栈:和虚拟机栈类似,虚拟机栈为Java方法服务,本地方法栈为native方法服务。
堆:是虚拟机管理内存最大的一块,是线程共享区域,存储对象实例。可以细分为新生代和老生代,是GC管理的主要区域。
方法区:是线程共享区域,存储类信息,常量,静态变量等数据。
以上都是运行时数据区。
2. 队列和栈:队列是只能在一段插入数据,另一端删除数据的线性表(先进先出)。栈是只能在一端进行插入和删除操作的线性表(先进后出)。
3. 双亲委派模型:当一类加载器收到类加载请求的时候,首先不会自己加载,把请求交给父类完成,直到没有父类加载器,子加载 器才会尝试自动加载。优势:避免类的重复加载,防止java核心api库被篡改。(类的加载过程)
4. java中的引用类型:
强引用:java中常用的就是强引用,当前引用有效就不会被回收。
软引用:使用SoftReference定义,当内存不够时,会将其回收;用来实现缓存技术。
弱引用:使用WeakReference 定义,GC执行时会直接回收掉。
虚引用:随时可能被回收,不可以用来创建对象。
5. 怎么判断对象是否可以被回收:通过堆中的树形结构,不可达到的对象可以被回收。
6. jvm中的垃圾回收算法:
标记清除:先从根节点遍历,将存活对象进行标记,将未被标记的对象清除。存活对象多的情况下,比较高效;容易产生内存碎片,扫描空间两次。
复制算法:标记所有存活对象,将存活对象复制到一块新的内存中,将原来的内存全部回收掉。存活对象较少比较高效,扫描空间一次。需要一块空的内存空间,并复制移动。
标记整理:在标记清除算法上做了优化,将标记的对象压缩到内存的一端,然后清理边界外的对象。
分代收集算法:目前虚拟机的算法,根据不同的代使用上述三种回收算法。年轻代使用复制算法,老年代使用标记清除或标记整理。
7. GC回收机制
年轻代(-Xmn设置年轻代大小)分为Eden区和两个survivor区(from和to),内存空间比例为8:1:1(可以通过参数–XX:SurvivorRatio设置)。新创建的对象会存放到Eden区,执行一次(当eden区对象满了的时候)minor GC会将存活对象保存到from区,如果from区放不下,会直接放到老年代,eden区的内存全部回收掉。之后新来的对象放到继续Eden区,from满了的时候,将eden和from中存活的对象放到to区,然后将两个区交换,保持to区是空的,to区放不下,就都放到老年代,回收掉eden和from中的对象。当对象被复制一定次数(默认15次,可以设置),就会进入老年代。当老年代满了的时候会触发full GC,效率很低,要尽可能防止其触发。新生代都用minor GC不会影响老年代。full GC在老年代满了或永久代满了或调用System.gc()时会触发。
8. jvm垃圾回收器
Serial:是最基本的收集器,是一个单线程收集器,他运行时必须暂停其他所有的线程,直到运行完成。
parnew:是serial的多线程版本。
Parallel Scavenge:使用复制算法的多线程收集器。自适应调节策略是它和parnew的最大区别,不需要设置新生代的大小,比例,年龄等参数。
serial old:使用标记整理算法,老年代使用。cms收集器的后被预案,发生Concurrent Mode Failure时执行。
parallel old:是parallel scavenge的老年代版本。使用多线程和标记整理算法。
cms:cms收集器使用标记清除算法,分为初始标记(GC root能直接关联的对象),并发标记(多线程标记GC root间接关联的对象),重新标记(并发重新检查标记),并发清除(并发清除)。并发标记和重新标记会暂停所有线程。老年代占用超过92%执行。
优点:并发收集,低停顿。
缺点:会产生大量的空间碎片,无法清除浮动垃圾,对cpu要求较高。
G1:堆内存划分为大小相等的区域,年轻代和老年代不在物理隔离。优点:并行和并发,分代收集,空间整理(标记整理,复制算法),可预测停帧。老年代执行步骤:初始标记,并发标记,最终标记,筛选回收。年轻代就是复制算法。