JVM简答

一、内存模型

JVM内存区域



1.1 线程私有区域

1.Program Counter Register(程序计数器)。一块较小的内存空间,作用是当前线程所执行字节码的行号指示器。

2. Java Stack(虚拟机栈)。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行时会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息. 每个方法被调用至返回的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

3. Native Method Stack(本地方法栈)。本地方法栈则为Native方法服务。但HotSpot VM直接就把本地方法栈和虚拟机栈合二为一。

1.2 线程共享区域

1. Method Area(方法区)。即我们常说的永久代(Permanent Generation),用于存储被JVM加载的类信息常量静态变量即时编译器编译后的代码等数据。

2. Heap(Java堆)。几乎所有对象实例和数组都要在堆上分配。是垃圾收集器的主要活动区域。java堆细分为新生代老年代,新生代又分为Eden空间、From Survivor空间、To Survivor空间。新生代中垃圾回收算法为复制算法,复制算法是先将内存分为两个部分,一部分用来放入对象,而另一部分暂时不用,当使用的一部分内存要进行垃圾回收的时候会将不需要回收的对象复制保存在另一个空间中,然后再对使用过的那部分区域进行垃圾回收,这样虽然效率很高,但是很浪费空间,所以一般将新生代分为Eden空间和两个Survivor空间,其大小在HotSpot虚拟机中默认比例为8:1:1,这样在新生代中采用复制算法回收垃圾效率就很高了,具体回收过程是将Eden区域和From Survivor区域作为对象的存储空间,当要进行垃圾回收的时候先将这两个区域中不需要回收的对象复制保存在To Survivor区域中,然后再进行垃圾回收。另外有一点是当一个对象在Eden区域和From Survivor区域中存储的时候发现内存不足,这时会进行内存分配担保,就是将此对象直接存入在老年代中。

老年代中采用的GC算法为标记-整理算法。先对要进行GC的对象进行标记,然后将不需要GC的对象移动到一端,然后在边界外再对要回收的对象进行GC。

关于对象的分配:对象优先在Eden区域分配,大对象会直接进入老年代,长期存活的对象会进入老年代,这里的长期存活是根据新生代中的对象年龄阈值来定义的,对象刚分配到新生代的时候年龄为1,每进行一次GC对象的年龄会加1,HotSpot中默认的阈值是15,也就是说对象年龄达到15岁的时候会被分配到老年区,这个值是可以通过参数配置的。

在进行垃圾回收的时候新生代GC又叫minor GC,老年代GC可以设置内存容量达到百分比的多少的时候进行GC,老年代的GC又叫Full GC,minor GC时间短,频率高,而Full GC时间长,频率低。

可达性分析算法:以“GC Roots“的对象为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明这个对象不可达,即这个对象不可用,所以这个对象会被判定为是可回收对象。

GC Roots:GC管理的主要区域是Java堆,一般情况下只针对堆进行垃圾回收。方法区、栈和本地方法区不被GC所管理,因而选择这些区域内的对象作为GC roots,被GC roots引用的对象不被GC回收。

虚拟机栈(栈帧中的本地变量表)中引用的对象;
方法区中类静态属性引用的对象;
方法区中常量引用的对象;
本地方法栈中JNI(即一般说的Native方法)引用的对象;

二、类加载过程


1.加载:
一句话,通过类的全限定名将Class文件加载到内存,并生成Class对象
虚拟机需要完成以下3件事情:
  1. 通过一个类的全限定名来获取定义此类的二进制字节流(并没有指明要从一个Class文件中获取,可以从其他渠道,譬如:网络、动态生成、数据库等);
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
  3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;
2.验证
这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
3.准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在堆中。其次,这里所说的初始值“通常情况”下是数据类型的零值
4.解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
5.初始化
到了初始化阶段,才真正开始执行类中定义的java程序代码。
6.使用
7.卸载

三、类加载器

1.启动类加载器(Bootstrap ClassLoader)
负责加载 JAVA_HOME\lib 目录中,且被虚拟机认可(按文件名识别,如rt.jar)的类。
2.扩展类加载器(Extension ClassLoader)
负责加载 JAVA_HOME\lib\ext 目录中的。
3.应用程序类加载器(Application ClassLoader)
负责加载用户路径(classpath)上的类库。

 类加载器之间的这种层次关系,称为类加载器的双亲委派模型(Parents Delegation Model)。双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。这里类加载器之间的父子关系一般不会以继承(Inheritance)的关系来实现,而是都使用组合(Composition)关系来复用父加载器的代码。
 双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
 使用双亲委派模型来组织类加载器之间的关系,有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户自己编写了一个称为java.lang.Object的类,并放在程序的ClassPath中,那系统中将会出现多个不同的Object类,Java类型体系中最基础的行为也就无法保证,应用程序也将会变得一片混乱。


参考:http://blog.csdn.net/zjf280441589/article/details/53437703

参考:http://www.importnew.com/18548.html  这个很好,我很受用

参考:http://www.importnew.com/25295.html 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值