目录
JVM是什么,JVM的体系结构
Java平台可分为两部分,即Java虚拟机和java API类库
JVM是Java Virtual Machine的缩写,JVM是一种用于计算机设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
Java虚拟机主要分为五大模块:类装载器子系统、运行时数据区、执行引擎、本地方法接口和垃圾收集模块
JVM整体认知图
JDK是Java程序员常用的开发包,目的就是用来编译和调试JAVA程序的
JRE是指Java运行环境,写好的程序必须在JRE才能够运行
JVM是Java虚拟机的缩写,是指负责将字节码解析成为特定的机器码进行运行,值得注意的是在运行过程中,Java源程序需要通过编译器编译为.class文件。
类加载器
加载class文件
对象变回class
双亲委派机制
当一个.class文件被加载时
结论: AppClassLoder–>Ext–>Boot(最终执行)
应用程序加载器,扩展类加载器,根加载器,虚拟机自带的加载器
类加载器收到请求
将请求向上委托给父类加载器去完成,一直向上委托,直到启动自动类加载器
启动加载器检查是否能够加载当前这个类。能加载就结束,使用当前的加载器,否则抛出异常,通知子加载器进行加载
双亲委派机制的作用
防止重复加载同一个.class。通过委托去向上问一句加载过了,就不用在加载一遍了。保证数据安全
保证核心.class不能被篡改。通过委托方式,不会去篡改核心.class,即使篡改也不会去加载,即使加载也不会是同一个.class对象。不同加载器加载同一个.class也不是同一个class对象。这样保证了Class执行安全。
沙箱安全机制
组成沙箱的基本组件
字节校验器:确保Java类文件遵循JAVA语言规范。这样可以帮助Java程序实内存保护。但并不是所有的类文件都会经过字节码校验,比如核心类
类加载器:其中类加载器在三个方面对java沙箱起作用
它防止恶意软件代码去干涉善意代码;
守护被信任的类库边界
将代码归入保护域,确定了代码可以进行哪些操作
存取控制器:存取控制器可以控制核心API对操作系统的存取权限。而这个控制的策略设定,可以由用户指定。
安全管理器:是API和操作系统之间的主要接口。实现权限控制,比存取孔子器优先级高。
安全软件包:java.security下的类和扩招包下的类,允许用户为自己的应用增加新的安全特性,包含:安全提供者 消息摘要 数字签名 加密 鉴别
虚拟机运行时数据区
Native
方式带有native关键字的,说明Java的作用范围已经达不到了,会去调用底层c语言的库,会进入本地方法栈 ,调用本地方法接口JNI。JIN作用:扩展Java的使用,融合不同编程语言Java所用。Java诞生的时候C、C++盛行,想要立足,必须要有调用C、C++的程序,它在内存区域中专门准别了一块标记区域:Native Method Stack,登记native 方法。最终执行的时候,加载本地方法库中的方法通过JNI.
PC寄存器
程序计数器:program counter register
每个线程都有一个程序计数器,是线程私有的,就是一个指针,指针指向方法区中的方法字节码(用来存储指向一条指令的地址,也即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。
方法区Method Area
方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,简单来说,所有定义的方法信息都存在该区域,此区域属于共享区间;静态变量、常量、类信息(构造方法、接口定义),运行时的常量池存在方法区中,但是实例变量存在对内存中,和方法区无关。
栈heap
栈内存,主管程序的运行,生命周期和线程同步;线程结束,栈内存也就是释放,对于栈来说,不存在垃圾回收问题,一旦线程结束,栈就over。栈内存中存在:8大基本类型+对象引用+实例的方法
栈运行的原理:栈帧
栈满:StackOverflowError
栈帧图解:栈底部子帧指向上一个栈的方法,上一个栈的父帧指向栈底部方法
三种JVM:Sun公司HotSpot Java Hotspot™ 64-Bit Server VM (build 25.181-b13,mixed mode) ●BEA JRockit ●IBM J9VM 我们学习都是: Hotspot
堆
一个JVM只有一个堆内存,堆内存的大小是可以调节的;类加载器读取文件后
方法区:存放类、方法、常量及变量
堆中:保存我们所有引用类型的真实对象(对象实例)
堆内存还要细分为三个区:新生区(伊甸园去),
- 伊甸园Eden、辛存区from及辛存区to(from–>to 动态交替的)
老年区,永久区
新生区:
新生区诞生和成长的地方,甚至是死亡
伊甸园:所有的对象都是在伊甸园创建new出来的
老年区:
当伊甸园存满且经过GC(垃圾回收区)后,没有被GC回收的对象存幸存区
当第一步把幸存区存满后对象将反放入老年区
说明:经过研究验证:99%的对象都是临时对象;说明大部分对象在伊甸园区被回收
永久区:
这个区域常驻内存,用来存在JDK自身携带的Class对象、interface元数据、存储的是java运行的一些环境或类信息,这个区域不存在来不及回收。关闭虚拟机就会释放这个区域的内存
出现OOM(内存溢出)的情况:
一个启动类加载了大量的第三方jar包,Tomcat部署了太多的应用,大量动态生成反射类,不断地被加载器加载
jdk1.6以前:有永久区,常量池在方法区
jdk1.7:有永久区,但是慢慢退化‘去永久区’,常量池在堆中
jdk1.8及以后:无永久区,常量池在元空间
在一个项目中,突然出现了OOM故障,那么该如何排除
能够看到代码第几行出错:内存快照分析工具,MAT, Jprofiler ●Dubug, 一行行分析代码
MAT, Jprofiler作用:分析Dump内存文件,快速定位内存泄露;获得堆中的数据 ,获得大的对象~
Jprofile使用
1.在idea中setting-plugins下下载jprofile插件 2.联网下载jprofile客户端 3.在idea中VM参数中写参数 -Xms1m -Xmx8m -XX: +HeapDumpOnOutOfMemoryError 4.运行程序后在jprofile客户端中打开找到错误告诉哪个位置报错(show in explorer)
常用参数说明:
-Xms5m:设置初始化内存分配大小5m;默认为1/64
-Xmx10m:设置最大分配内存10m;默认1/4
-XX:+PrintGCDetails :打印GC垃圾回收
-XX:+HeapDumpOnOutOfMemoryError :Dump报错信息
-XX:MaxTenuringThreshold=5 :更改辛存区到老年区的阈值
GC垃圾回收
GC的算法有哪些?标记清楚发、标记压缩、复制算法、引用计数器
轻GC和重GC分别在什么时候发生?
引用计数法
给每个对象分配一个计数器,计数器本身也有消耗,所以并不高效不常用
复制算法
谁空是是to
第一次GC后,Eden区和to区空,经过15此垃圾回收后依然存活下来的对象就会去养老区
好处:没有内存的碎片
坏处:浪费内存空间(一个幸存区的空间永远是空)
复制算法最佳使用场景:对象存活度较低的时候
标记清除算法
优点:不需要而外的空间
缺点:两次扫描严重浪费时间,会产生时间碎片
改进:标记清除再压缩
压缩是防止内存碎片产生,再次扫描,向一端移动存活的对象多了一个移动成本
总结:
内存效率:复制算法>标记清除算法>标记压缩算法
内存整齐度:复制算法=标记压缩算法>标记清除算法
内存利用率:标记压缩算法=标记清除算法>复制算法
最合适的算法 —> GC:分代收集算法