JVM
什么是JVM?
-
JVM是一种虚拟出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
-
JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java语言最重要的特点就是跨平台运行。
-
使用JVM就是为了支持与操作系统无关,实现跨平台。
JRE
Java平台,所有java程序都要在JRE环境下才能开发
JDK
是开发者用来编程、调试程序用的开发包。JDK也是Java程序需要在JRE上运行
JVM的原理
Java编译器将Java代码转换成字节码文件。通过JVM将每条指令翻译成不同的机器码,通过特定平台运行
JVM内存模型
程序计数器
能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置
是每个线程私有的,由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。
Java栈
Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息
本地方法栈
本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的
堆
Java中的堆是用来存储对象本身的以及数组(数组引用是存放在Java栈中的)。堆是被所有线程共享的,在JVM中只有一个堆。
方法区
与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。
在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息是常量池,用来存储编译期间生成的字面量和符号引用。
在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。
JVM的垃圾回收机制
不定时去堆内存中清理不可达对象
System.gc(); // 手动回收垃圾
finalize()方法
finalize()方法是在每次执行GC操作之前时会调用的方法,可以用它做必要的清理工作。
如何判断对象是否存活
应用计数法(主流虚拟机没有使用)
—引用计数法就是如果一个对象没有被任何引用指向,则可视之为垃圾。这种方法的缺点就是不能检测到环的存在。
概念: 每个对象在创建的时候,就给这个对象绑定一个计数器。每当有一个引用指向该对象时,计数器加一;每当有一个指向它的引用被删除时,计数器减一。这样,当没有引用指向该对象时,计数器为0就代表该对象死亡
优点: 引用计数算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法
缺点: 主流的Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题
可达性分析法
—该种方法是从GC Roots开始向下搜索,搜索所走过的路径为引用链。当一个对象到GC Roots没用任何引用链时,则证明此对象是不可用的,表示可以回收
可以作为GC Roots 的对象:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象;
- 方法区中类静态属于引用的对象;
- 方法区中常量引用的对象;
- 本地方法栈中JNI(即一般说的Native方法)引用的对象。
- 等
优点:
- 解决相互循环引用问题。
缺点:
- 目前和引用计数法比没得缺点
垃圾回收机制策略
引用技术算法
概念:
每个对象在创建的时候,就给这个对象绑定一个计数器。每当有一个引用指向该对象时,计数器加一;每当有一个指向它的引用被删除时,计数器减一。这样,当没有引用指向该对象时,计数器为0就代表该对象死亡,这时就应该对这个对象进行垃圾回收操作。
优点:
- 实现简单,判定效率也很高
缺点:
- 主流的Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题。
标记–清除算法
概念:
为每个对象存储一个标记位,记录对象的状态(活着或是死亡)。
分为两个阶段,一个是标记阶段,这个阶段内,为每个对象更新标记位,检查对象是否死亡;第二个阶段是清除阶段,该阶段对死亡的对象进行清除,执行 GC 操作。
优点:
- 可以解决循环引起的问题
- 必要时才回收(没有内存时)
缺点:
- 回收时,应用需要挂起
- 标记和清除的效率不高,尤其是要扫描的对象比较多的时候
- 会造成内存碎片(会导致明明有内存空间,但是由于不连续,申请稍微大一些的对象无法做到)
标记–整理算法
概念:
标记清除算法和标记压缩算法非常相同,但是标记压缩算法在标记清除算法之上解决内存碎片化(有些人叫"标记整理算法"为"标记压缩算法")
标记-整理法是标记-清除法的一个改进版。同样,在标记阶段,该算法也将所有对象标记为存活和死亡两种状态;不同的是,在第二个阶段,该算法并没有直接对死亡的对象进行清理,而是将所有存活的对象整理一下,放到另一处空间,然后把剩下的所有对象全部清除。这样就达到了标记-整理的目的。
优点:
- 解决标记清除算法出现的内存碎片问题
缺点:
- 压缩阶段,由于移动了可用对象,需要去更新引用
复制算法
概念:
该算法将内存平均分成两部分,然后每次只使用其中的一部分,当这部分内存满的时候,将内存中所有存活的对象复制到另一个内存中,然后将之前的内存清空,只使用这部分内存,循环下去。
这个算法与标记-整理算法的区别在于,该算法不是在同一个区域复制,而是将所有存活的对象复制到另一个区域内。
优点:
- 在存活对象不多的情况下,性能高,能解决内存碎片和java垃圾回收算法
标记-清除算法
中导致的引用更新问题
缺点:
- 会造成一部分的内存浪费。不过可以根据实际情况,将内存块大小比例适当调整;如果存活对象的数量比较大,复制算法的性能会变得很差。
查考博客:http://t.csdn.cn/E58t6