Java内存分析:虚拟机运行时数据区算法
1)程序计数器(Program Counter Register):能够看作当前线程所执行的字节码的行号指示器 工做:经过改变这个计数器的值来选取下一条须要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 说明:程序计数器是线程私有的。每条线程都须要有一个独立的程序计数器,各条线程间的计数器互不影响,独立储存。 举例:若是线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令地址;若是正在执行的是native方法,这个计数器值则为空。 2)Java虚拟机栈:描述的是Java方法执行的内存模型。 工做:每一个方法在执行的同时都会建立一个栈帧(Stack Frame)用于储存局部变量表、操做数栈、动态连接、方法出口等信息,每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈道出栈的过程。 说明: 1)Java虚拟机栈是线程私有的,它的生命周期与线程相同。 2)通常人们所说的“栈”就是指虚拟机栈,或者指虚拟机栈中局部变量表部分 局部变量表存放了编译期可知的各类基本数据类型(boolean、byte、char、int..)、对象引用等 异常:虚拟机栈中规定了两种异常情况: 1)若是线程请求的栈深度大于虚拟机所容许的深度,将抛出StackOverflowError异常; 2)若是虚拟机栈能够动态扩展(当前大部分的Java虚拟机均可以动态扩展),若是扩展时没法申请到足够的内存,就会抛出OutOfMemoryError异常 3)本地方法栈(Native Method Stack):为虚拟机使用到的Native方法服务。 说明:与虚拟机栈的区别:虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。 Sun HotSpot虚拟机直接就把本地方法栈和虚拟机栈合二为一。 异常:与虚拟机栈中规定的异常相同。 4)Java堆:是被全部线程共享的一块内存区域,在虚拟机启动时建立。惟一的目的就是存放对象实例 如今收集器基本都采用分代收集算法 Java堆分为新生代、老年代 新生代(Young generation) 结构:Eden空间、From Survivor空间、To Survivor空间 特色:新生代中大部分的对象是“朝生夕死”的,每次垃圾收集时都发现有大批对象死去,只有少许存活 老年代(Tenured generation) 特色:老年代中的对象存活率高、没有额外空间对它进行分配担保。 注:新生代GC(Minor GC)、老年代GC(Full GC、Major GC) 5)方法区(永久代:Permanent Generation):用于储存已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 说明: 1)与Java堆同样,方法区是各个线程共享的内存区域。 2)Java虚拟机规范把方法区描述为堆的一个逻辑部分,可是它却有一个别名叫作 Non-Heap(非堆) 运行时常量池:是方法区的一部分 方法区的回收: 主要回收:废弃的常量、无用的类 废弃常量:没有任何引用关联着的常量即废弃常量。 无用的类:同时知足如下3个条件的类 1)该类全部的实例都已经被回收,也就是说Java堆中不存在该类的任何引用。 2)加载该类的ClassLoader已经被回收 3)该类对应的Class对象没有再任何地方被引用,没法在任何地方经过反射访问该类的方法。 注:知足条件的类是否会被回收,由虚拟机设定:由 -Xnoclassgc 参数进行控制。 重要:在大量使用反射、动态代理(jdk动态代理、cglib动态代理等)、动态生成jsp 的场景中都须要虚拟机具有类卸载功能,以保证方法区不会溢出。