JVM
java概述
java体系
java程序语言java虚拟机实现class文件格式java类库api第三方类库javaSEjavaEEjavaMEjava历史
1991年4月 James Gosling博士领导的绿色计划(Green Project)开始启动 java的前身oak 95年的互联网兴起
1995年5月23日。Oak语言改名为Java,并且在SunWorld大会上正式发布Java 1.0版本。Java语言第一次提出了“Write Once,Run Anywhere”的口号。
1996年1月23日,JDK 1.0发布,Java语言有了第一个正式版本的运行环境。JDK 1.0提供了一个纯 解释执行的Java虚拟机实现(Sun Classic VM)。JDK 1.0版本的代表技术包括:Java虚拟机、Applet、 AWT等。
1996年4月,十个最主要的操作系统和计算机供应商声明将在其产品中嵌入Java技术。同年9月, 已有大约8.3万个网页应用了Java技术来制作。在1996年5月底,Sun于美国旧金山举行了首届JavaOne大会,从此JavaOne成为全世界数百万Java语言开发者每年一度的技术盛会。
1997年2月19日,Sun公司发布了JDK 1.1,Java里许多最基础的技术支撑点(如JDBC等)都是在 JDK1.1版本中提出的,JDK 1.1版的技术代表有:JAR文件格式、JDBC、JavaBeans、RMI等。Java语言的语法也有了一定的增强,如内部类(Inner Class)和反射(Reflection)都是在这时候出现的。
直到1999年4月8日,JDK 1.1一共发布了1.1.0至1.1.8这9个版本。从1.1.4以后,每个JDK版本都有 一个属于自己的名字(工程代号),分别为:JDK 1.1.4-Sparkler(宝石)、JDK 1.1.5-Pumpkin(南瓜)、JDK 1.1.6-Abigail(阿比盖尔,女子名)、JDK 1.1.7-Brutus(布鲁图,古罗马政治家和将军) 和JDK 1.1.8-Chelsea(切尔西,城市名)。
java虚拟机家族
虚拟机始祖:Sun Classic/Exact VM武林盟主:HotSpot VM小家碧玉:Mobile/Embedded VM天下第二:BEA JRockit/IBM J9 VM软硬合璧:BEA Liquid VM/Azul VM挑战者:Apache Harmony/Google Android Dalvik VM没有成功,但并非失败:Microsoft JVM及其他JAVA内存区域和内存溢出异常
JAVA内存分配
线程独享
虚拟机栈 栈根 方法访问的时候有相关的逻辑 局部变量表字符串数组长度知道,存储的指针或者句柄,32位,长度时固定的。访问的时候需要限定为指针和句柄(对象数组也是这样的) 本地方法栈 本地方法—native方法 一般C++写 程序计数器 每个线程的方法不一样执行的字节码的行号机器流程控制的指示器为线程切换之后能正确的执行位置 所有需要没有线程有一个独立的线程计数器,互不影响唯一没有内存溢出错误的区域线程共享
方法区 类型信息static 修饰 final 修饰回收性价比很低 堆 垃圾回收 int a = 3 分场景存储普通方法 入栈类中 入堆 在对象创建时进入运行时常量池表
是方法区的一部分 。存放字面量和符号引用 如String a = “aaaaa” 其中的aaaaa就是字面变量
可以在运行期间可以将新的常量进入池中。最多在String类的intern()方法。
当常量池无法申请到内存会抛出异常
直接内存
-Xmx 参数hotspot虚拟机
对象创建
遇到new指令之后,检查参数可不可以定位到类的符号 如果有如果没有 通过之后 分配内存如果java堆时绝对规整的则指针碰撞如果java堆时一块一块的 则 使用空闲列表带有控件压缩整理 就是指针碰撞 简单高效清除算法 空间列表可能线程不安全 可以使用TLAB分配空间,预先分配一块内存。使用完了采用同步锁定 TLAB 通过-xx :+/-UserTLAB参数设定内存分配完了 就是将分配的控件初始话为零(对象头不用),如果使用TLAB可以在分配时同时完成局部变量没有初始值,成员变量有初始值。对象内存布局
对象头 对象运行时数据(Markword) 哈希码GC粉黛年两锁状态标记线程持有的所动态的定义数据结构,可以复用 对象指向它的类型元数据的指针 知道属于那个类型的通过对象所属类的信息实例数据
实际储存对象的有效信息根据一个规定好的顺序排序父类优先子类可以父类的空隙中对其填充
实际数据可能不够对象的定位
句柄
好处 对象移动时会好 句柄池 指向类型指向实例 实例单独存放直接指针(hotspot使用)
移动需要修改java栈中的数据好处 移动快 java栈直接指向存储实例,并且其中有一个指向类型的指针垃圾回收和内存分配策略
三问
那些内存需要回收什么时候回收如何回收当高并发习引起错误是需要堆监控和调节
那些该回收
活着死去两种方法
引用计数器
虽然需要一些额外的控件计数但是效率高java没有使用缺点 很难解决对象的循环引用问题比如对象内相互指向但是外部实例置为空了
可达性分析算法
使用GC root作为根节点,如果节点不可达及为死亡
虚拟机栈 引用的对象
方法去京台面两引用的对象
方法去常量引用的对象
本地方法栈中国JNI应用的对象
java虚拟机内部的应用
基本数据对应的Class对象,常驻异常对象
所有被同步持有的对象
反映java虚拟机内部情况的JM XBean,JVM TI中注册的回调,本地代码。
支持局部回收的特征,需要将关联的都添加到GC Roots 避免过多做过优化
四种引用
强引用 只要有就绝不回收当内存不够就报错 软引用 有用但是非必须在内存溢出之前会回收如果还不够就抛出异常 弱引用 垃圾回收就会被回收 虚引用 在被回收之后有一个系统通知 完成一个实例,并且在java中找一下应用的实例。为什么这么设计?对象的自我拯救
public static void main(String[] args) throws Throwable {SAVE_HOOK = new Main();SAVE_HOOK = null;System.gc();Thread.sleep(500);if(SAVE_HOOK != null){SAVE_HOOK.isAlive();}else{System.out.println("no,i am dead");}SAVE_HOOK = null;System.gc();Thread.sleep(500);if(SAVE_HOOK != null){SAVE_HOOK.isAlive();}else{System.out.println("i not dead once , but now,i am dead");}}public static Main SAVE_HOOK = null;public void isAlive(){System.out.println("yes,i am stall alive");}@Overrideprotected void finalize() throws Throwable{super.finalize();System.out.println("finalize if executed");Main.SAVE_HOOK = this;}
如上 对象第一次拯救成功,因为重写了finalize方法,在第一次回收会执行他自己的finalize方法。第二次在回收就必定会被回收。所有对象的fianlize方法之后被执行一次。
垃圾回收不是立即执行的,想队列添加一个,优先级很低
回收方法区
常量回收
类型
所有实例都被回收类加载器都被回收了java。lang Class对象没有在任何地方被引用,无法通过反射访问该类的方法
Java虚拟机被允许对满足上述三个条件的无用类进行回收,这里说的仅仅是“被允许”,而并不是
和对象一样,没有引用了就必然会回收。关于是否要对类型进行回收,HotSpot虚拟机提供了-
Xnoclassgc参数进行控制,还可以使用-verbose:class以及-XX:+TraceClass-Loading、-XX:
+TraceClassUnLoading查看类加载和卸载信息,其中-verbose:class和-XX:+TraceClassLoading可以在
Product版的虚拟机中使用,-XX:+TraceClassUnLoading参数需要FastDebug版[1]的虚拟机支持。