初识JVM虚拟机
面试经常会问到,对JVM的了解
其实无非问的最多的是:
1.jvm的内存区域分配
2.jvm的GC
3.jvm的调优
JVM的内存区域分配
先放一张偷来的图,哈哈~
先了解什么是jvm?
JRE有java API和JVM组成,JVM通过类加载器(Class Loader)加载类Java应用,并通过Java API进行执行。
JVM本身就是一个用于执行java字节码的执行器。
由上图可以看出:
JVM的内部体系结构分为三部分,分别是:类装载器子系统、运行时数据区和执行引擎。
类装载器子系统:每一个java虚拟机都由一个类加载子系统,负责加载程序中的类型(类和接口),并赋予唯一的名字。JVM的两种类装载器包括:启动类装载器和用户自定义类装载器,启动类装载器是JVM实现的一部分,用户自定义类装载器则是Java程序的一部分,必须是ClassLoader类的子类。
执行引擎:负责执行被加载类中包含的指令。
运行时数据区:堆、方法区、本地方法栈、虚拟机栈、程序计数器。
其实我们的重点是运行时数据区!!!
再偷一张图,哈哈~
现在说JVM的运行内存区域分配?
堆:线程共享,存放所有程序运行时创建的对象以及数组值的区域,堆中的对象内存需要等待GC进行回收。
方法区:线程共享,又称持久态,当JVM的类装载器加载class文件并进行解析,把解析的类信息、静态变量、常量等等存入方法区,在一定条件下也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OOM的错误信息。
程序计数器:线程私有,又叫PC寄存器,每个线程都有自己的PC寄存器,也是该线程启动时创建的,寄存器的内容总是指向下一条将执行指令的地址,若线程执行java方法,则PC保存下一条执行指令的地址,若执行native方法,则PC的值为undefined
虚拟机栈:线程私有,存放的为当前线程中方法局部基本类型的变量、部分返回的结果
本地方法栈:线程私有,存储本地方法调用的状态
JVM的GC
GC的问题比较多,我们一个一个来
1.什么是GC?
垃圾回收机制
将垃圾对象进行回收,释放内存,防止内存泄漏,有效的使用可以使用的内存,对内存中已死亡的或者长时间没有使用的对象进行清除和回收。
2.关于GC判断垃圾的算法
引用计算法:
通过在对象中分配一个空间来保存该对象被引用的次数,如果该对象被其他对象引用,引用计数+1,如果删除对该对象的引用,引用计数-1,当该引用计算为0时,那么该对象就会被回收(缺陷:相互引用的情况下,引用计数永不为0)。
可达性分析算法:
可达性分析算法的基本思路是,通过一些被称为引用链的对象作为起点,从这些起点开始向下搜索,搜索走过的路径被称为Reference Chain,当一个对象到GC Roots没有任何引用链相连时,(即从GC Roots节点代该节点不可达)则证明该对象不可用
在Java中,可作为GC Roots的对象包括以下几种:
- 虚拟机栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI引用的对象
3.关于GC回收的算法
标记-清除法:
是最基础的一种垃圾回收算法,分为两部分,先把内存区域中的这些对象进行标记,那些属于可回收的
标记出来,然后把标记出来的垃圾进行清理掉(缺陷:产生内存碎片,内存需要连续的)。
复制算法:
将内存按容量分为大小相等的两块,每次只使用其中的一块,当这块的内存用完了,就将还存活的对象复制到另一块上面,然后将已使用的内存空间一次清理掉,保证了内存的连续性(缺陷:只使用一般,代价太高)。
标记-整理法:
标记过程仍然和标记清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都想一端移动,在清理端边界以外的内存区域(缺陷:内存变动频繁,需要整理所有存活对象的引用,效率低)。
分代收集算法:
简单来说,这不算是一种算法,而是一种根据各个算法的优点总结出来的方案。
将对象存活周期的不同将内存划分为N块,一般是将对分为新生代和老年代,这样就可以就可以根据各个年代的特点采用最适当的收集算法,在新生代中,每次垃圾收集时,都有大批对象死去,只用少量存活,那就选择复制算法,只需要付出少量的存活对象的复制成本,而老年代中因为存活效率高,没有额外的空间对它进行分配担保,就必须使用标记-清除法或者标记-整理法来进行回收。
4.新生代、老年代和持久代?
年轻代:年轻代分为三个区,一个Eden区,两个Survivor区。大部分对象在Eden区生成。当Eden区满时,还存活的对象将被复制到Survivor区,当这个Survivor区也满的时候,从第一个Survivor区复制过来的并且还存活的对象,将被复制到年老区。(两个Survivor分别是From区和To区)。
年老代:年老代存放从年轻代存活的对象,一般来说年老代存放的都是生命周期较长的对象。
持久代:用于存放静态文件,如java类、方法等。持久代对垃圾回收没有显著影响。
将内存中不再被使用的对象进行回收,GC用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对象的生命周期特征进行分析后,按照新生代、旧生代的方式进行对对象的收集,以尽可能的缩短GC对应用造成的暂停
- 对新生代的对象的收集称为minor GC
- 对旧生代的对象的收集称为Full GC
- 程序中主动调用System.gc()强制执行的GC为Full GC
不同的对象引用类型,GC会采用不同的方法进行回收,JVM对象的引用类型分为四种:
- 强引用:默认情况下,对象采用的均为强引用(这个对象的实力没有其他对象引用,GC时才会被回收)
- 软引用:软引用是Java中提供的一种比较适合于缓存场景的引用(只用在内存不够用的情况下才会被GC)
- 弱引用:在GC时一定会被GC回收
- 虚引用:由于虚引用只是用来得知对象是否被GC
未完待续。。。