目录
一、虚拟机的理解
二、java如何实现跨平台机制
三、JVM内存区域
四、JVM栈和堆的区别
五、垃圾回收是在哪个区域发生,讲一下垃圾回收?
六、垃圾回收算法
七、cms和g1的区别
虚拟机其实就是通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境下的完整计算机系统。只要是在实体计算机上能实现的功能,虚拟机基本都能实现。
JVM虚拟机主要是由类加载器、运行时数据区、执行引擎和本地方法接口四个部分组成。
它的主要特点首先可以跨平台使用,可以运行在不同的计算机系统,如Linux、MacOS等。
跨语言不管是什么编程语言经过编译转换为的字节码文件,他都能识别。
java的跨平台其实是因为JVM。因为不同的平台使用的JVM不一样。
通常java源代码编译后的文件为字节码文件。而JVM可以将字节码文件翻译成当前平台下的机器码运行。而我们只需要在不同平台下安装相应的JVM,就可以运行字节码文件。
JVM内存区域分为两种一种为线程共享的区域,一种为线程私有的区域。
线程共享的区域有堆区和元空间。
其中堆区的话是jvm中最大的一块区域,也是存放对象实例以及数组的地方。而堆区中又分为老年代和新生代,他们的占比分别为2:1,在老年代中存放的一般是一些不容易被删除的对象,老对象,而新生代存放的则是一些新创建的对象,容易被删除的对象。在新生代中也划分为3个区域Eden区和两个相同的Survivor区,他们的占比分别为8:1:1。
元空间的话存放的是一些常量、静态变量、类信息、JIT即时编译器编译后的机器代码等。
线程私有的区域有虚拟机栈、本地方法栈、程序计数器。
虚拟机栈它是由一个个栈帧组成,每个栈帧都拥有局部变量表、操作数栈、动态连接和方法返回地址。而被调用一个方法,对应的栈帧都会被压入虚拟机栈、而当方法结束后,又会从虚拟机栈中弹出。最顶层的栈帧代表着当前正在执行的方法,这些栈帧其实就相当于方法的调用,调用一个方法一个栈帧入栈,当这个方法彻底结束,栈帧又会被弹出,回到调用它的那个栈帧中。
本地方法栈也是存放一个个栈帧,不过该栈帧所对应的方法是由native修饰的本地方法。
程序计数器则是用于记录当前线程所执行的字节码的行号,它主要由两个用处,一个是用于多线程的情况下,用于切换线程时记录当前执行的位置,方便下次执行时从当前位置继续执行。另一个则是用于实现代码的流程控制,循环、异常等,通过行号的切换实现执行位置的跳转。
首先堆和栈是两个不同的区域,堆是线程共享的区域,而栈是线程私有区域。
堆存放的是对象的实例和数组,而栈存放的则是一个个栈帧。而栈帧中存放是局部变量、操作数栈、动态链接和方法返回值。
垃圾回收发生的区域为堆和元空间,主要是在堆中,一般在堆中的新生代发生次数比较多,老年代发生概率比较低。
而当一个对象没有什么用处时,则该对象就是需要被回收的垃圾对象。JVM默认使用可达性分析算法来推断这个对象是否需要回收。(可达性分析算法其实就是定义一系列称为“GC Roots”的根对象为起始节点。对一个对象通过引用关系向上寻找,如果没有找到这个GC Roots则说明这个对象为垃圾对象)。
垃圾回收是指不同的垃圾收集器通过不同的算法来对垃圾对象进行处理。
垃圾回收算法主要分为三种
标记-清除算法他是先将不需要回收对象先标记起来,标记完成后,清除所有未标记的对象。如果这个区域大部分都是需要回收的对象,那么这种算法的效率就会很低下。而这个会造成空间碎片化问题,导致产生大量不连续的空间,如果有一个大的对象需要分配,就无法找到连续足够的空间。
标记-复制算法是先将空间分为完全一样大小的两块空间,每次使用只是用其中一块,在一块使用完后,先将不需要回收的对象复制到另一块中,然后清除这块空间。这个算法可以改善空间碎片化问题,但是会浪费过多的空间,使现在只能是原来一般,而且如果不需要回收的对象,如果较多化,效率会很低。
标记-整理算法也是先标记所有不需要回收的对象,然后将所有标记的对象向着一端移动,最后清除边界以外的内存。这种算法也是可以防止空间碎片化问题。
首先使用范围不一样,CMS收集器是用于老年代的收集器,可以配合Serial和PaeNew收集器使用。G1收集器则可以用于老年代也可以用于新生代。不需要结合其他收集器使用。
STW(Stop The World)的时间,CMS收集器是以最小停顿时间为目的的收集器,G1收集器可预测垃圾回收的停顿时间(建立可预测的停顿时间模型)。
垃圾回收算法不同,CMS收集器使用的是标记-清除算法,容易产生内存碎片。而G1收集器使用的是标记-整理算法,降低了内存空间碎片。
垃圾回收的过程不同,CMS收集器依次是初始标记、并发标记、重新标记、并发清除。而G1收集器则是初始标记、并发标记、最终标记、筛选回收。
注:本篇文章都是我自己的理解,可能用词和语句不够严谨,如有错误请评论指正,谢谢!(持续更新中......)