就是 JAVA 虚拟机, 它只识别 .class 类型文件,它能够将 class 文件中的字节码指令进行识别并调用操作系统向上的 API 完成动作。
Java 源代码 -> 编辑器 -> 字节码文件
字节码 -> JVM -> 机器码文件
每一种平台的解释器是不同的,但是实现的虚拟机是相同的,这也就是 Java 为什么能够 跨平台的原因
线程私有数据区域生命周期与线程相同, 依赖用户线程的启动/结束 而 创建/销毁(在 Hotspot VM 内
线程共享区域随虚拟机的启动/关闭而创建/销毁
运行时常量池(Runtime Constant Pool)是方法区的一部分。
Java虚拟机栈是描述Java方法运行过程的内存模型。 Java虚拟机栈会为每一个即将运行的方法分配“栈帧”空间,用于保存改方法运行过程中所需要的一些信息,例如局部变量、操作数栈、动态链接、方法出口信息等。
Java虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。
局部变量表的创建是在方法被执行的时候,随着栈帧的创建而创建。而且,局部变量表的大小在编译时期就确定下来了,在创建的时候只需分配事先规定好的大小即可。
Java虚拟机栈会出现两种异常: StackOverFlowError OutOfMemoryError
StackOverFlowError:当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就抛出StackOverFlowError异常。
OutOfMemoryError: 若Java虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常。
线程共享 :整个Java虚拟机只有一个堆,所有的线程都访问同一个堆。
在虚拟机启动时创建。 垃圾回收的主要场所。 不同的区域存放具有不同生命周期的对象。这样可以根据不同的区域使用不同的垃圾回收算法,从而更具有针对性,从而更高效。 堆的大小既可以固定也可以扩展,但主流的虚拟机堆的大小是可扩展的,因此当线程请求分配内存,但堆已满,且内存已满无法再扩展时,就抛出OutOfMemoryError。
方法区中存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。
方法区是堆的一个逻辑部分,因此和堆一样,都是线程共享的。整个虚拟机中只有一个方法区。
方法区中的信息一般需要长期存在,而且它又是堆的逻辑分区,因此用堆的划分方法,我们把方法区称为老年代。
对方法区的内存回收的主要目标是:对常量池的回收 和 对类型的卸载。长期存在。
方法区中存放数据:类信息、常量、静态变量、即时编译器编译后的代码。其中常量存储在运行时常量池中。
常量池存在于方法区。
复制 , 清空, 互换
MinorGC 采用复制算法。
首先,把 Eden 和 ServivorFrom 区域中存活的对象复制到 ServicorTo 区域(如果有对象的年 龄以及达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1(如果 ServicorTo 不 够位置了就放到老年区);
然后,清空 Eden 和 ServicorFrom 中的对象;
最后, ServicorTo 和 ServicorFrom 互换,原 ServicorTo 成为下一次 GC 时的 ServicorFrom 区。
老年代的对象比较稳定,所以 MajorGC 不会频繁执行。在进行 MajorGC 前一般都先进行 了一次 MinorGC,使得有新生代的对象晋身入老年代,导致空间不够用时才触发。
MajorGC 采用标记清除算法:首先扫描一次所有老年代,标记出存活的对象,然后回收没 有标记的对象。 MajorGC 的耗时比较长,因为要扫描再回收。 MajorGC 会产生内存碎片,为了减 少内存损耗,我们一般需要进行合并或者标记出来方便下次直接分配。当老年代也满了装不下的 时候,就会抛出 OOM(Out of Memory)异常。
主要存放 Class 和 Meta(元数据)的信息,Class 在被加载的时候被 放入永久区域, 它和和存放实例的区域不同,GC 不会在主程序运行期对永久区域进行清理。所以这 也导致了永久代的区域会随着加载的 Class 的增多而胀满,最终抛出 OOM 异常。
当对象在 Survivor 区躲过一次 GC 后,其年龄就会+1。 默认情况下年龄到达 15 的对象会被 移到老生代中。
Java8 中, 永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。元空间 的本质和永久代类似,
因此,默认情况下,元空间的大小仅受本地内存限制。
在 Java 中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单 的办法是通过引用计数来判断一个对象是否可以回收。简单说,即一个对象如果没有任何与之关 联的引用, 即他们的引用计数都不为 0, 则说明对象不太可能再被用到,那么这个对象就是可回收 对象。
为了解决引用计数法的循环引用问题, Java 使用了可达性分析的方法。通过一系列的“GC roots” 对象作为起点搜索。如果在“GC roots”和一个对象之间没有可达路径,则称该对象是不可达的
不可达对象不等价于可回收对象, 不可达对象变为可回收对象至少要经过两次标记 过程。
JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化。
当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父 类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中, 只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的 Class), 子类加载器才会尝试自己去加载。
Concurrent mark sweep(CMS)收集器是一种年老代垃圾收集器,其最主要目标是获取最短垃圾 回收停顿时间,和其他年老代使用标记-整理算法不同,它使用多线程的标记-清除算法。 最短的垃圾收集停顿时间可以为交互比较高的程序提高用户体验。 CMS工作机制相比其他的垃圾收集器来说更复杂,整个过程分为以下4个阶段:
Garbage first 垃圾收集器是目前垃圾收集器理论发展的最前沿成果,相比与CMS 收集器,G1 收 集器两个最突出的改进是: