java虚拟机-jvm内存回收算法篇

第一章 走进JAVA
java的优点:摆脱了硬件平台的束缚,实现了“一次编写,到处运行”;它提供了一个相对安全的内存管理和访问机制,避免了绝大部分的内存泄漏和指针越界问题;它实现了热点代码检测和运行时编译及优化,这使得java应用能随着运行时间的增加而获得更高的性能 。
1 java虚拟机发展史
1.1 Sun Classic/Exact VM(jdk1.0~jdk1.2)
世界上第一款商用java虚拟机,它只能使用纯解释器方式来执行Java代码,如果要使用JIT编译器,就必须进行外挂,但是外挂JIT后,JIT编译器就会完全接管虚拟机的执行系统,解释器就不工作了 。由于Classic VM不能和JIT配合工作,这就意味着如果要使用编译器执行,编译器就不得不对每一个方法、每一行代码都进行编译,而无论他们执行的频率是否具有编译的价值 。基于程序响应时间的压力,这些编译器不敢用编译耗时稍高的优化技术,即使用了JIT,其执行效率也和C++有很大差距 。
1.2 Sun HotSpot VM
HotSpot VM继承了Sun之前两款商用虚拟机优点,HotSpot指是的它的热点代码探测技术 。HotSpot VM的热点代码探测技术可以通过执行计数器找出最有编译价值的代码,然后通知JIT编译器以方法为单位进行编译,如果一个方法被频繁调用,或方法中的有效循环次数很多,将会分别触发标准编译和OSR编译动作 。通过编译与解释器恰当的协同工作,可以在最优化的程序响应时间和最佳执行性能取得平衡,而且无需等待本地代码输出才能执行程序,即时编译的时间压力也相对减小,这样有助于更多的代码优化技术秘输出质量更高的本地代码 。
2 模块化
它是解决应用系统与技术平台越来越复杂、越来越庞大 的一个重要途径 。
【java虚拟机-jvm内存回收算法篇】3 64位虚拟机
几年之前,java程序运行在64位虚拟机上需要付出比较大的额外代价:首先是内存问题,由于指针和各种数据类型对齐补白的原因,运行于64位系统上的java应用程序需要耗费更多的内存,通常要比32位系统额外增加10%~30%的内存消耗;其次,64位虚拟机性能也全面落后于32位 。
第二章 Java内存区域与内存溢出异常
2.1 概述
对于java程序员来说,在虚拟机自动内存管理机制下,不再需要为每一个new操作,去写配对的delete/free代码,不容易出现内存泄漏和内存溢出问题,由java虚拟机管理内存 。但是也正是java程序员把内存控制权交给了java虚拟机,一旦出现内存泄漏和溢出方面的问题,不了解虚拟机是怎样实用内存的,那么排查错误会是一项艰难的工作 。
2.2运行时数据区域

java虚拟机-jvm内存回收算法篇

文章插图
 
程序计数器(线程私有内存区域): 程序计数器(Program Counter Register) 是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器 。在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条执行字节码指令 。每条线程都有一个独立的程序计数器,独立存储,互不影响,因此这类内存区域被称为线程私有的内存 。如果执行的是java方法,这个计数器记录的是正在执行的虚拟机字节码指令地址 。如果是native方法,计数器为空 。此内存区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域 。
Java虚拟机栈(线程私有内存区域):与程序计数器一样,它也是线程私有的,它的生命周期和线程相同 。同样是线程私有,描述Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息 。一个方法对应一个栈帧 。在java虚拟机规范中,对这个区域规定了两种异常情况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机可以动态扩展,如果扩展时无法申请到足够的内存,则会抛出OutOfMemoryError异常 。
本地方法栈(Native Method Stack):和Java虚拟机栈很类似,虚拟机栈为虚拟机执行java方法,不同的是本地方法栈为Native方法服务 。与虚拟机栈一样,本地方法栈也会抛出StackOverflowError异常和OutOfMemoryError异常 。
Java堆:是Java虚拟机所管理的内存中最大的一块 。由所有线程共享,在虚拟机启动时创建 。堆区唯一目的就是存放对象实例 。堆中可细分为新生代和老年代,再细分可分为Eden空间、From Survivor空间、To Survivor空间 。堆无法扩展时,抛出OutOfMemoryError异常 。


推荐阅读