JVM虚拟机的体系结构
1.方法区,方法区主要存方以下信息:
1). 这个类的全限定名
2).这个类型的访问修饰符
3).字段信息(字段名,类型,修饰符P)和方法信息(方法名,返回类型,参数数量和类型,修饰符)。
4).除了常量以外的所有类的静态变量。
2.堆区
Java程序在运行时所创建的所有对象实例都i放在同一个堆中,所有线程共享这个堆。优化虚拟机性能的主要工作是优化堆内存使用效率。
3.栈区
当我们启动一个线程时,Java虚拟机会为我们配一个Java 栈。
Java 栈区中存储了线程中方法调用得到状态,包括局部变量,参数,返回值等。栈由许多栈帧组成,一个栈帧包含一个Java方法调用的状态。当线程调用一个方法时,虚拟机压入(push)一个新的栈帧到该线程的Java栈中,当该方法返回时,这个栈帧就从Java栈中弹出(pop)。
如果线程请求的栈帧深度大于允许的深度,那么虚拟机就抛出StackOverflowError
4.程序计数器
java程序运行时,程序计数器总是指向下一条被执行指令的地址。
5.本地(方法)接口和本地方法栈
本地方法也称本地接口(Java Native Interface ,JNI). Java 线程可以调用本地方法,我们可以在Java线程中通过本地方法接口调用本地C++定义好的方法。
6.执行引擎
执行引擎也称字节码执行引擎,用来执行字节码。
7.类加载子系统
类加载子系统(也称类加载器)主要分为启动类加载器(BootStrapClassLoader),扩展类加载器
(Extension ClassLoader),应用程序类加载器(Application ClassLoader)和用户自定义的类加载器(User Defined ClassLoader).
和类加载器相关的两个异常:如果找不到类文件,会报 ClassNotFoundExecption异常;
如果加载到的类中引用到的其他类不存在,则会报NoClassDelFoundError异常。
分代管理和 Java垃圾收集机制
堆内存结构:
堆内存分代管理持久代(也称持久区)中主要存放的是Java类信息,或者在代码中通过import导入的类信息.
在年轻代中一般会划分伊甸区和两个Survivor区
垃圾回收的一般流程
(1) new 出来的对象我们一般先到伊甸区Eden中申请空间,如果申请不到怎么办? 会把伊甸区中存活的对象复制到其中一个Survivor区中. 这里隐含了一个回收流程,当我们把伊甸区的对象复制到Survivor区时,把无用的对象回收了.
(2)当伊甸区和其中一个Survivor区满了,会把伊甸区和其中一个Survivor区存活的对象再复制到另外一个Survivor区中,同样隐含了一次回收流程.
(3) 如果年轻代的空间都满了,虚拟机会把年轻代中还存活的对象复制到年老代中
(4) 当年老代满时(不会再复制到持久代了),会启动Full GC ,对年轻代\年老代\持久代进行全面回收.这耗费较长时间
在上述的回收流程中,其实包含两类回收机制.
1).轻量回收(Minor GC). 在年轻代中的回收都属于这种.这种回收中,一般都会用到一种效率相对较高的标记复制算法(Mar Copy),这种算法不涉及对无用对象的删除,只是把标记存活的对象从一个内存区复制到另一个内存区.
2).重量级的Full GC流程,以下四种情况会触发这种GC
2.1) 年老代(Tenured)被写满
2.2)持久代被写满
2.3)程序员显示的调用了Systerm.gc()方法.
2.4)可以通过java命令分配堆空间的运行策略,如可以设置年轻代和年老代的比例,如果虚拟机监控到上次GC后,这种运行策略发生变化,也会触发Full GC.
不重视内存性能可能会导致严重后果
年轻代和年老代都写满了会触发FullGC,在执行FullGC时,会导致"Stop the World"情况的发生,也就是说虚拟机终止了所有Java程序,专门执行Full GC ,这就是卡住的原因.
判断对象是否可以回收的依据
标准很简单: 当某个对象存在强引用的情况时,不能回收.否则可以回收. 在绝大多数场景中,当某个对象上的最后一个强引用被撤去后,该对象不会被立即回收,而是在下次启动垃圾回收机制时候被回收.
早期Java版本,采用"引用计数法 "来判断对象是否被引用. 很简单,对象被引用一次,加1.未被引用则为0.
但有个缺点,无法解决"循环引用的情况". a引用b , b引用 c, c引用a
后续JDK版本,引入"根搜索算法".从根节点GC ROOT 开始寻找 引用的节点,直到找到最后一个节点. 未被找到节点也就是未被引用的节点,可以被回收.
可以作为GC Root 对象有以下四个:
1.虚拟机中引用的对象.
2.方法区中静态属性引用的对象.
3.方法区中常量引用的对象
4.本地方法栈中引用的对象.
深入了解finalize方法:
finalize() 是Object 类中的protected 类型的方法,子类可以通过覆盖整个方法来实现回收前的资源清理工作,与这个方法相关的流程如下:
1) Java 虚拟机一旦通过"根搜索算法",判断出某对象处于可以回收的状态时,会判断该对象是否重写了
Object 类的finalize 方法,如果没有,则直接回收.
2).如果重写了finalize方法,而且未执行方法,则把该对象放到F-Queue 队列,另一个线程会定时遍历F-Queue队列,并执行队列中各对象的finalize方法.
3).finalize方法执行完毕后,GC会再次判断该对象是否可被回收,如果可以,则进行回收;如果此时该对象上有强引用,则该对象"复活",即处于"不可回收状态".
网友评论