Java在各个平台上是如何跑起来的?
我们都知道 Java 源文件,通过编译器,能够生产相应的.Class 文件,也就是字节码文件, 而字节码文件又通过 Java 虚拟机中的解释器,编译成特定机器上的机器码
不同平台上的解释器不同,但是虚拟机环境是相同的,这就是java为什么能在各个平台上运行的原因
JVM允许一个应用并发执行多个线程
JVM 内存区域主要分为线程私有区域【程序计数器、虚拟机栈、本地方法区】、线程共享区 域【JAVA 堆、方法区】、直接内存
JVM的多线程处理提高了程序的并行处理效率
程序计数器(线程私有)
一块较小的内存空间, 是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为线程私有的内存
正在执行 java 方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址),如 果还是 Native 方法,则为空
这个内存区域是唯一一个在虚拟机中没有规定任何 OutOfMemoryError 情况的区域
程序计数器的作用是用于存储下一条指令(即java代码编译完成的字节码指令)的地址,方便虚拟机解释器找到这些指令并且翻译成机器码交给CPU执行
虚拟机栈(线程私有)
是描述java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame) 用于存储局部变量表、操作数栈、动态链接、方法出口等信息
每一个方法从调用直至执行完成 的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程
一个方法域都对应一个栈帧,每次方法执行结束,栈帧内存放的变量引用都会被GC机制回收,回收结束后,对应的强引用也会消失(不可达),便于GC机制继续回收那些不可达的对象占用的堆内存
本地方法栈则为 Native 方法服务,调用本地其它语言的方法,例如C++,C等
Java提供了本地调用需要实现的接口(JNI)Java Native Interface ,它允许Java代码和其他语言写的代码进行交互
是被线程共享的一块内存区域,创建的对象和数组都保存在 Java 堆内存中,也是垃圾收集器进行 垃圾收集的最重要的内存区域
堆内存通常存放new关键字创建的对象数据
堆内存分为 新生代 (Eden 区、From Survivor 区和 To Survivor 区)和 老年代
在了解堆内存内的分代回收机制前,先要了解下垃圾回收机制如何判断一个对象是否存活
第一次标记
如果对象在进行可达性分析后发现没有与GC Roots(对象引用关系链,相当于一个树结构)相连接的引用链, 那它将会被第一次标记,随后进行一次筛选
GCroot原理:通过对枚举GCroot对象做引用可达性分析
可以作为GC root对象的有:
- 局部变量(Object obj = new Object() 中的obj)引用的对象
- 静态属性引用的对象 (static修饰的属性)
- 方法区常量引用的对象(static+final修饰的属性)
- 本地方法栈中引用的对象
新生代(8:1:1)
Eden区(伊甸区)
ServivorFrom区(幸存者1区)
ServivorTo区(幸存者2区)
GC机制在新生代中的运行过程
1、将Eden区和ServivorFrom区中的数据复制到ServivorTo区,对象年龄+1,如果有达到老年区对象标准的移至老年区(默认15次扫描后)
2、清空Eden区和ServivorFrom区数据
3、替换ServivorFrom区和ServivorTo区数据内容
在第一次标记的同时我们要明白GC机制还做了一件事情:
判断是否要执行finalize()
方法
finalize()是Object的protected方法
finalize()
与C++中的析构函数不是对应的。C++中的析构函数调用的时机是确定的(对象离开作用域或delete掉),但Java中的finalize的调用具有不确定性
finalize()
方法才能被回收
finalize()
方法,那么该对象将会被放置在一个F-Queue队列中,稍后由一个虚拟机自动建立的、低优先级的Finalizer线程去执行它
finalize()
方法,或者finalize()
方法已经被虚拟机调用过,此时会被认
定为没必要执行finalize()
方法
对象可由两种状态,涉及到两类状态空间
一是终结状态空间 F = {unfinalized, finalizable, finalized}
二是可达状态空间 R = {reachable, finalizer-reachable, unreachable}
各状态含义如下:
unfinalized: 新建对象会先进入此状态,GC并未准备执行其finalize方法,因为该对象是可达的 finalizable: 表示GC可对该对象执行finalize方法,GC已检测到该对象不可达。正如前面所述,GC通过F-Queue队列和一专用线程完成finalize的执行 finalized: 表示GC已经对该对象执行过finalize方法 reachable: 表示GC Roots引用可达 finalizer-reachable(f-reachable):表示不是reachable,但可通过某个finalizable对象可达 unreachable:对象不可通过上面两种途径可达
第二次标记
第二次标记会为执行完finalize()
方法的对象进行最后一次标记,之后销毁该对象内存
老年代
新时代与老年代的内存比例为1:2
老年代的对象比较稳定,所以 MajorGC 不会频繁执行
MajorGC(采用标记复制回收策略)触发条件
频繁触发MajorGC的原因一般为:新生代内存不足以存放过大内存占用率的对象,或者是没有合理分配好新生代的对象内存
元空间并不在虚拟机中,而是使用本地内存,其大小仅受本地内存限制
G1 收集器 Garbage first 垃圾收集器是目前垃圾收集器理论发展的最前沿成果,相比与 CMS 收集器,G1 收 集器两个最突出的改进是:
G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域 的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域,区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收集效率