Java-----JVM基础
Posted 小鹿可可乐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java-----JVM基础相关的知识,希望对你有一定的参考价值。
JVM
1.JVM介绍
1.1JVM概念:
JVM即java虚拟机:JVM是利用软件来模拟计算机OS和硬件平台,在上面执行字节码文件,JVM有自己的架构,有堆栈,寄存器及指令系统
1.2 JVM特点
跨平台性:Java的跨平台性体现在Java代码“一次编译,到处执行”JVM是属于Java应用和操作系统中间的纽带的作用,将Java代码编程成字节码放在JVM上执行,JVM负责将字节码文件翻译为特定平台的机器码执行
2.JVM 工作过程
2.1 类加载系统
类加载机制:将Java的字节码文件.class加载到JVM中
类不会被初始化:
- 同一个类在一个JVM实例中只会去被加载初始化一次
- 在编译时能够确定的静态变量,不会对类进行初始化
2.1.1 类加载时机
- 创建对象实例:New对象,前提是类被加载过
- 通过class文件反射创建对象
- 调用类静态属性或静态方法时
- 初始化一个类的子类,使用子类时先初始化父类
- 被标记为启动类的类,如main方法所在类
2.1.2 类加载
1.类加载器:
- Bootstrap ClassLoader:启动类加载器:加载JDK包中/jre/lib/rt.jar中所有类
- Extension ClassLoader:扩展类加载器:加载扩展功能的jar
- Application ClassLoader:应用类加载器:负责加载classpath中指定的jar和目录中的class
2.双亲委派模型
- 当前的类加载器从自己已经加载的类中查询是否此类已经加载,如果已经加载则返回原来已经加载的类
- 如果没有找到,就去委派父类加载器去加载。父类加载器也会采用同样的策略,查看自己已经加载的类中是否包含这个类。有则返回,没有就委托其父类去加载。直到委托到启动类加载器为止。应因如果父类加载器为空,代表使用启动类加载作为父类去加载该类
- 如果启动类加载器加载失败,就回会去使用扩展类加载器来尝试加载。继续失败则会使用APP ClassLoader来加载,如果存在自定义加载器就会到自定义加载器去尝试加载。继续失败就回去抛出一个异常:ClassNotFoundException.
双亲委派模型的优势:安全性、避免类重复加载
2.1.3 类加载过程
1、加载:通过双亲委派机制将字节码文件加载到内存中
2、连接
- 验证:验证元数据,字节码,符号引用
- 准备:对类静态变量分配内存,初始化默认值
- 解析:将符号应用转化为直接引用
3、初始化:类的静态变量赋予正确的初始值
2.2 运行数据区域
2.2.1 内存模型
1.程序计数器:
- 线程私有
- 内存模型中占用内存最小的一个区域
- 是当前程序执行字节码的行号指示器,实现代码的流程控制
- 不会出现OutOfMemoryError的内存区域
- 随着线程创建产生,随着线程结束而死亡
2.虚拟机栈
- 线程私有
- 是有一个个帧栈组成,每个帧栈是一个方法,用来描述程序方法执行的模型帧栈包含:局部变量表(数据类型,对象应用,返回地址)、操作数栈、动态链接、方法出口信息
- 异常:StackOverflowError:虚拟机栈的内存不允许动态扩容,栈内存不够时抛出该异常OutOfMemoryError:虚拟机栈的内存允许动态扩容,栈内存不够(无法扩展)时抛出异常
- 随着线程创建产生,随着线程结束而死亡
3.本地方法栈
- 线程私有
- 作用和虚拟机栈一样,区别在于执行时Native的方法服务
- 异常:StackOverflowError:虚拟机栈的内存不允许动态扩容,栈内存不够时抛出该异常OutOfMemoryError:虚拟机栈的内存允许动态扩容,栈内存不够(无法扩展)时抛出异常
- 随着线程创建产生,随着线程结束而死亡
4.堆
- 线程共享
- 内存模型中占用内存区域最大的空间
- 堆用来存放对象实例以及数组都存储在堆中
- 会抛出OutOfMemoryError异常
- 虚拟机创建是产生,虚拟机结束时销毁
5.方法区
- 线程共享
- 存储类信息,常量、静态变量存放在方法区
- 会抛出OutOfMemoryError异常
- 虚拟机创建是产生,虚拟机结束时销毁
2.垃圾回收
2.1 GC原理
1.将内存中不在被使用的对象进行回收,GC回收的方法称之为收集器,GC过程主要是回收对象,即主要是针对对空间,GC过程需要消耗资源和时间
2.Minor GC:对新生代的对象的收集
3.Full GC:对老年代的对象的收集,强制GC执行(System.gc)也是Full GC
2.2 对象被标记为垃圾的方法
1.引用计数器:存在无法解决循环引用问题
2.可达性分析
*从GCRoots遍历堆中对象,遍历完后没有被引用的节点即视为垃圾
*GC root:
- 1、虚拟机栈中引用对象
- 2、本地方法栈中的JNI引用对象
- 3、方法区中静态变量和常量引用的对象
2.3 垃圾回收算法
2.3.1 标记清除
将对象回收分为标记和清除阶段,
标记阶段通过可达性分析标记从GCroot对象开始遍历所有可达的对象
清除阶段对对内存再次遍历,对未标记的对象进行回收
缺点:
- 内存碎片化
- 效率问题:两个阶段都是遍历堆的整个空间
2.3.2 复制算法
将堆内存空间分成大小两部分,每次使用其中一块,当这块快用完时,将存活的对象复制到另一个内存块中,将原对象空间一次性清除
优势:
- 解决内存碎片化问题
- 提高效率:每次只需要遍历堆空间的一半
缺点:
- 内存缩小为原来一半,浪费空间,代价高
- 极端情况,对象百分百存活就需要整个空间复制,耗时代价高
2.3.3 标记整理算法
将对象回收分为标记和整理两个阶段,标记阶段使用可达性分析遍历整个对=堆空间找到可达的对象,整理阶段将所有存活的对象向一段进行移动
优势:
- 空间整个使用
- 解决内存碎片化问题
缺点:
- 效率不高,需要标记存活对象,遍历内存找到所有存活对象进行移动整理
2.3.4 分代回收算法
1.根据对象的存活时间的特点将内存空间划分为老年代和新生代
2.新生代:对象存活时间段,朝生夕灭-采用复制算法进行回收
3.老年代:经过多次GC存活下来的对象,存活时间上,采用标记清除或标记整理算法
3.JVM系统调优
3.1 调优原则
- 多数的应用不需要进行服务器上进行GC调优
- GC引起的问题多数是代码问题
- Java服务在部署之前都需要考虑将机器的JVM参数设置最优
- 减少创建对象的数量
- 减少使用全局变量和大对象
- GC调优是最优的额优化手段
- 在实际中,分析GC情况比优化GC要多
3.2 调优步骤
- 监控GC,内存使用等关键信息
- 分析结果,给出优化方案
- 调整GC类型和内存分配
- 需要不断分析调整
今天也要好好学习呀~
以上是关于Java-----JVM基础的主要内容,如果未能解决你的问题,请参考以下文章