JVM
-
内存结构:线程共享和线程独占。
共享的有:方法区,堆;
独占的有:虚拟机栈,本地方法栈,程序计数器。
/*
JDK1.7中,对于Hotspot虚拟机,方法区由永久代实现,JDK1.8时,永久代被移除采用了元空间。
元空间使用的时计算机的直接内存,脱离了Java虚拟机内存独立存在的。
为什么要替换成元空间呢?答:因为永久代是有固定上限的,而随着动态类加载情况越来越多,十分容易内存溢出,但设置太大了又容易浪费,我们直接使用计算机内存,受本机的内存限制,内存溢出的几率变小。
*/
JDK1.7,字符串常量池被单独拿出来放到了堆中,但好像本体是在本地内存的。
-
类加载的过程:加载,连接,初始化,使用,卸载。//书上只写了加载,验证,准备,解析,初始化。
其中,连接还分为:验证,准备,解析。
加载:1. 通过一个类的全限定名来获取定义此类的二进制字节流。
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3.在内存中生成一个代表这个类的java.lang.Class对象(一个类或一个接口被装入jvm时产生,存有其详细信息,存在方法区里面!),作为方法区这个类的各种数据的访问入口。
//数据不需要类加载创建。
加载完成后,类的加载信息便存到了方法区之中,数据格式由虚拟机实现自行定义。
验证在加载阶段尚未完成就已经开始,大致如:1.文件格式验证(是否符合class文件格式规范)2.元数据验证(是否有父类,父类是否继承了final类,是否实现了接口的所有方法)3.字节码验证(能否正常跳转,类型转换是否有效)4.符号引用验证(权限访问,public)。
准备:对被static修饰的变量(类变量)进行内存分配,(通常情况下)初始化零值,不包括实例变量;如 static int value = 123,value 初始化为0!,特殊情况为 ,类字段的字段属性表存在ConstantValue属性,如加上了 final关键字,则为123。
解析:将常量池的符号引用替换为直接引用。page:220。
初始化:是类加载的最后一步,也是真正执行类中定义的 Java 程序代码(字节码),初始化阶段是执行类构造器< cint>
()
方法的过程。卸载即该类的Class对象被GC。
卸载类需要满足3个要求:
- 该类的所有的实例对象都已被GC,也就是说堆不存在该类的实例对象。
- 该类的 java.lang.Class 对象没有在其他任何地方被引用
- 该类的类加载器的实例ClassLoader已被GC
-
对象创建:1. 类加载检查2.分配内存3.内存空间初始化为零值(不包括对象头)4.对象设置(对象头包括:GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID等,还有类型指针,即对象指向它的类元素的指针)
-
判断对象死亡:1.引用计数算法。2. 可达性分析(不可达时,也并非一定要死P66,可通过finalize()重新连接CG ROOT。 一个对象的finalize()只能执行1次,只有特殊情况下我们需要实现这个方法进行关闭连接,资源回收,如socket连接。)。
-
强引用,软引用,弱引用,虚引用。