Java虚拟机内存模型及回收机制,只需呀一篇文章就能搞懂!

23 篇文章 0 订阅
21 篇文章 0 订阅

 

 

1.平台无关性

(1)为什么要先编译成java字节码再解析成机器码

a.准备工作:每次执行都需要各种检查。

因为编译的过程本来就是在进行编译以及检查的过程,如果直接对java代码解析成机器码,岂不是每次解析的时候都需要进行检查,何不提前检查好了,再进行解析

b.兼容性:也可以将别的语言解析成字节码

比如Clojure,Groovy, JRuby, Jython , Scala等他们最终会 通过不同的编译器(java是javac编译器)编译成 .class字节码在虚拟机进行运行

 

(2)JVM如何加载.class文件

java虚拟机:

a.JVM内存结构模型

JVM是内存中的虚拟机,可以理解为,JVM的存储就是内存,我们所有写的常量,变量,方法都在内存中

 

JVM架构:

Java虚拟机内存模型及回收机制

 

ClassLoader(类加载器): 依据特定的格式,加载class文件到内存

Runtime Data Area(运行数据区域):JVM内存空间结构模型

Execution Engine (执行引擎):对命令进行解析(解释器,对命令进行解析,能不能运行需要他来负责)

Native Interface(本机接口):融合不同开发语言的原生库为java所用,使用Class.forName()方法中的forName0()方法进行其他语言的类库的调用,返回值是native

 

类从编译到执行的过程(java从源码到运行共有三个阶段)

Java虚拟机内存模型及回收机制

 

编译器将*.java源文件编译为*.class字节码文件Source源码阶段

ClassLoader将字节码转换为JVM中的Class<对象名>对象(实质是byte数组)Class类对象阶段

JVM利用Class<对象名>对象实例化 * 对象加载到内存Runtime运行时阶段

ClassLoader

 

作用:

ClassLoader负责通过将Class文件的二进制数据流(使用io流进行读取的)装载进系统,然后交给java虚拟机进行连接,初始化操作(从系统外获取Class的二进制数据流)

种类:(Alibaba Dragonwell 是一款免费的 OpenJDK 发行版)

BootStrapClassLoader :C++编写,加载核心库java.*http://hg.openjdk.java.net/jdk8u/jdk8u/jdk==>browse==>src==>share==>native==>java.lang

ExtClassLoader :java编写,加载扩展库javax.* System.out.println(System.getProperty("java.ext.dirs"));

AppClassLoader :java编写,加载程序所在目录System.out.println(System.getProperty("java.class.path"));

自定义ClassLoader

Java虚拟机内存模型及回收机制

 

Java虚拟机内存模型及回收机制

 

双亲委派机制:

Java虚拟机内存模型及回收机制

 

1.自下向上*检查*类是否已经加载自定义ClassLoader==》AppClassLoader==》ExtClassLoader ==》BootStrapClassLoader

2.自上向下尝试*加载*类BootStrapClassLoader (jre/lib/rt.jar)==》ExtClassLoader(jre/lib/ext/*.jar) ==》AppClassLoader(classpath目录)==》自定义ClassLoader

 

小编总结:双亲委派机制:检查类是否加载的时候,顺序是自下而上的。如果是加载类的时候,顺序是自上而下的

 

有资料或文档需求的可以私信我哦(发送“资料”二字即可)

 

为什么要使用双亲委派机制:

1.避免多份同样字节码的加载(使用委托机制逐层去父类查找是否加载)

 

类的加载方式:(了解)

隐式加载:new (隐式调用类加载器将类加载带JVM)

显式加载:loadClass,forName等

loadClass和forName的区别:(了解)

Classloder.loadClass得到的class是没有链接的JDBCUtils.class.getClassLoader()//getResourceAsStream("druid.properties")

Class.forName得到的class是已经初始化完成的Class.forName("cn.itcast.utils.JDBCUtils")

 

JVM内存模型-JDK8:

 

1.程序计数器:

Java虚拟机内存模型及回收机制

 

作用:

1.当前线程所执行的字节码行号指示器(逻辑)

2.改变计数器的值来选取下一条需要执行的字节码指令

3.和线程是一对一的关系,即线程私有

4.对java方法技术,如果是Native方法,则计数器值为Undefined

5.不会发生内存泄漏

干什么用的:循环,跳转,异常处理,线程恢复 都是【程序计数器】通过【改变计数器的值】来实现的,命令指向的作用。

 

2.java堆(Heap):

对象实例分配区域

 

GC管理的主要区域

 

3.java虚拟机栈:

Java虚拟机内存模型及回收机制

 

1.java方法执行的内存模型,每个方法运行的时候都会创建一个栈帧【一个栈帧就相当于一个方法执行的时候,存在栈里面的状态】

 

2.包含多个栈帧,栈帧用来存储(局部变量表【局部变量存储的地方】,操作栈【进行运算的地方】,动态连接?????,返回地址)方法调用结束时,帧才会被销毁

 

局部变量表:包含方法执行过程中的所有变量

操作数栈:入栈,出栈,复制,交换,产生消费变量

递归为什么会引发java.lang.stackoverflowerror异常?

递归过深,栈帧数超出虚拟栈深度,方法调用层次过多

java.lang.OutOfMemoryError异常?

虚拟机栈开启过多,线程开启太多,导致内存不足以创建新的虚拟机栈

 

扩展:方法结束,栈帧会自动释放,栈的内存,不需要GC去回收

(jstack命令可以生成虚拟机当前时刻的线程快照,可以定位线程出现长时间停顿的原因,如线程间死锁,死循环,请求外部资源长时间的等待)

jmap

本地方法栈:

与虚拟机栈相似,只要作用于标注了native的方法

 

4.方法区:

方法区里面存储了类信息、静态变量、即时编译器编译后的代码(比如spring 使用IOC或者AOP创建bean时,或者使用cglib,反射的形式动态生成class信息等)等。

JDK1.7及以后,JVM已经将运行时常量池从方法区中移了出来,放到堆中

元空间(MetaSpace):【方法区的实现,可以理解为方法区是规定放什么东西,元空间是真正存放方法区规定东西的内存】

永久代:是HotSpot(虚拟机)的一种具体实现,实际指的就是方法区

元空间与永久代(PermGen)的区别

元空间使用本地内存,永久代使用的是JVM内存

元空间相比永久代的优势

1.字符串常量池存在永久代中,容易出现性能问题和内存溢出

2.类和方法的信息大小难易确定,给永久代的大小指定带来困难

3.永久代会为GC带来不必要的复杂性【不懂】

4.方便HotSpot与其他JVM如Jrockit的集成

 

扩展:

JVM三大性能调优参数 -Xms -Xmx -Xss的含义

命令演示:java -Xms128m -Xmx128m -Xss256k -jar ****.jar

-Xss:规定了每个线程虚拟机栈的大小,一般来说256k足够,此配置会影响此进程中并发线程数的大小

-Xms:堆的初始值 (如果堆的大小超出初始值的容量怎么办,会扩容到-Xmx配置的堆的内存最大值)

-Xmx:堆能达到的最大值,一般来说我们的初始值和最大值设置一样,以避免每次垃圾回收完成后JVM重新分配内存

 

java内存模型中堆和栈---内存分配策略(了解)

静态存储:编译时就能确定每个对象目标在运行时的存储空间需求

栈式存储:(动态存储)数据区需求,在编译时未知,运行时模块入口前确定

堆式存储:编译时或运行时,模块入口都无法确定,动态分配

 

java内存模型中堆和栈的联系:

Java虚拟机内存模型及回收机制

 

引用对象、数组时,栈里定义变量保存堆中目标的首地址

 

java内存模型中堆和栈的区别【重点】:

管理方式:栈自动释放,堆需要GC进行垃圾回收

空间大小:栈比堆小

碎片相关:栈产生的碎片远小于堆(内存不能及时释放产生的碎片,因为GC不是实时的)

分配方式:栈支持静态和动态分配,而堆仅支持动态分配

效率:栈的效率比堆高

 

2.GC【Garbage Collection】

对象被判定为垃圾的标准,没有被其他对象引用的情况下

怎么判定是否为垃圾的算法

 

a.引用计数算法(了解)

通过判断对象的引用数量来决定对象是否可以被回收

每个对象实例都有一个引用计数器,被引用则+1,完成引用则-1

任何引用计数为0的对象实例可以被当做垃圾收集

 

优点:执行效率高,程序执行受影响小

缺点:无法检测出循环引用的情况,导致内存泄漏

 

b.可达性分析算法(我们现在使用的是这个算法)

通过判断对象的引用链(GC Root)是否可达,来决定对象是否可以被回收

Java虚拟机内存模型及回收机制

 

如果GC Root判断对象是可达对象,就会将此对象标记为蓝色

如果GC Root判断对象是不可达对象,就会将此对象标记为灰色,标记为灰色的对象就会被GC回收

 

哪些对象可以作为GC Root对象

1.栈中引用的局部变量【方法里面的对象】【方法执行会被引用】

2.方法区中类【静态】属性引用的对象【类中的对象】【类加载会被引用】

3.方法区中常量引用的对象【常量】【类加载会被引用】

4.本地方法栈中JNI(即一般说的Native方法)引用的对象【native方法的引用】

 

 

 

就讲到这里啦~

希望可以帮到你们

有资料或文档需求的可以私信我哦(发送“资料”二字即可)

小编都会尽全力给你们解答哒~

或直接关注公众号【乐字节】(关注后记得一定要回复小编的暗号66哦!)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深入java虚拟机第二版 第1章 Java体系结构介绍 1.1 为什么使用Java 1.2 网络带来的挑战和机遇 1.3 体系结构 1.3.1 Java虚拟机 1.3.2 类装载器的体系结构 1.3.3 Java class文件 1.3.4 Java API 1.3.5 Java程序设计语言 1.4 Java体系结构的代价 1.5 结论 1.6 资源页 第2章 平台无关 2.1 为什么要平台无关 2.2 Java的体系结构对平台无关的支持 2.2.1 Java平台 2.2.2 Java语言 2.3.3 Java class文件 . 2.2.4 可伸缩性 2.3 影响平台无关性的因素 2.3.1 Java平台的部署 2.3.2 Java平台的版本 2.3.3 本地方法 2.3.4 非标准运行时库 2.3.5 对虚拟机的依赖 2.3.6 对用户界面的依赖 2.3.7 Java平台实现中的bug 2.3.8 测试 2.4 平台无关的七个步骤 2.5 平台无关性的策略 2.6 平台无关性和网络移动对象 2.7 资源页 第3章 安全 3.1 为什么要安全性 3.2 基本沙箱 3.3 类装载器体系结构 3.4 class文件检验器 3.4.1 第一趟:class文件的结构检查 3.4.2 第二趟:类型数据的语义检查 3.4.3 第三趟:字节码验证 3.4.4 第四趟:符号引用的验证 3.4.5 二进制兼容 3.5 Java虚拟机中内置的安全特性 3.6 安全管理器和Java API 3.7 代码签名和认证 3.8 一个代码签名示例 3.9 策略 3.10 保护域 3.11 访问控制器 3.11.1 implies()方法 3.11.2 检查示例 3.11.3 一个回答“是”的检查 3.11.4 一个回答“不”的检查 3.11.5 doPrivileged()方法 3.11.6 doPrivileged()的一个无效使用 3.12 Java安全模型的不足和今后的发展 方向 3.13 和体系结构无关的安全性 3.14 资源页 第4章 网络移动性 4.1 为什么要网络移动性 4.2 一种新的软件模式 4.3 Java体系结构对网络移动性的支持 4.4 applet:网络移动性代码的示例 4.5 Jini服务对象:网络移动对象的示例 4.5.1 Jini是什么 4.5.2 Jini如何工作 4.5.3 服务对象的优点 4.6 网络移动性:Java设计的中心 4.7 资源页 第5章 Java虚拟机 5.1 Java虚拟机是什么 5.2 Java虚拟机的生命周期 5.3 Java虚拟机的体系结构 5.3.1 数据类型 5.3.2 字长的考量 5.3.3 类装载器子系统 5.3.4 方法区 5.3.5 堆 5.3.6 程序计数器 5.3.7 Java 5.3.8 帧 5.3.9 本地方法 5.3.10 执行引擎 5.3.11 本地方法接口 5.4 真实机器 5.5 一个模拟:“Eternal Math” 5.6 随书光盘 5.7 资源页 第6章 Java class文件 6.1 Java class文件是什么 6.2 class文件的内容 6.3 特殊字符串 6.3.1 全限定名 6.3.2 简单名称 6.3.3 描述符 6.4 常量池 6.4.1 CONSTANT_Utf8_info表 6.4.2 CONSTANT_Integer_info表 6.4.3 CONSTANT_Float_info表 6.4.4 CONSTANT_Long_info表 6.4.5 CONSTANT_Double_info表 6.4.6 CONSTANT_Class_info表 6.4.7 CONSTANT_String_info表 6.4.8 CONSTANT_Fieldref_info表 6.4.9 CONSTANT_Methodref_info表 6.4.10 CONSTANT_InterfaceMethodref_ info表 6.4.11 CONSTANT_NameAndType_info 表 6.5 字段 6.6 方法 6.7 属性 6.7.1 属性格式 6.7.2 Code属性 6.7.3 ConstantValue属性 6.7.4 Deprecated属性 6.7.5 Exceptions属性 6.7.6 InnerClasses属性 6.7.7 LineNumberTable属性 6.7.8 LocalVariableTable属性 6.7.9 SourceFile属性 6.7.10 Synthetic属性 6.8 一个模拟:“Getting Loaded” 6.9 随书光盘 6.10 资源页 第7章 类型的生命周期 7.1 类型装载、连接与初始化 7.1.1 装载 7.1.2 验证 7.1.3 准备 7.1.4 解析 7.1.5 初始化 7.2 对象的生命周期 7.2.1 类实例化 7.2.2 垃圾收集和对象的终结 7.3 卸载类型 7.4 随书光盘 7.5 资源页 第8章 连接模型 8.1 动态连接和解析 8.1.1 解析和动态扩展 8.1.2 类装载器与双亲委派模型 8.1.3 常量池解析 8.1.4 解析CONSTANT_Class_info入口 8.1.5 解析CONSTANT_Fieldref_info 入口 S.1.6 解析CONSTANT_Methodref_info 入口 8.1.7 解析CONSTANT_Interface- Methodref_info入口 8.1.8 解析CONSTANT_String_info入口 8.1.9 解析其他类型的入口 8.1.10 装载约束 8.1.11 编译时常量解析 8.1.12 直接引用 8.1.13 _quick指令 8.1.14 示例:Salutation程序的连接 8.1.15 示例:Greet程序的动态扩展 8.1.16 使用1.1版本的用户自定义类装 载器 8.1.17 使用1.2版本的用户自定义类装 载器 8.1.18 示例:使用forName()的动态扩展 8.1.19 示例:卸载无法触及的greeter类 8.1.20 示例:类型安全性与装载约束 8.2 随书光盘 8.3 资源页 第9章 垃圾收集 9.1 为什么要使用垃圾收集 9.2 垃圾收集算法 9.3 引用计数收集器 9.4 跟踪收集器 9.5 压缩收集器 9.6 拷贝收集器 9.7 按代收集的收集器 9.8 自适应收集器 9.9 火车算法 9.9.1 车厢、火车和火车站 9.9.2 车厢收集 9.9.3 记忆集合和流行对象 9.10 终结 9.11 对象可触及性的生命周期 9.11.1 引用对象 9.11.2 可触及性状态的变化 9.11.3 缓存、规范映射和临终清理 9.12 一个模拟:“Heap of Fish” 9.12.1 分配鱼 9.12.2 设置引用 9.12.3 垃圾收集 9.12.4 压缩堆 9.13 随书光盘 9.14 资源页 第10章 和局部变量操作 10.1 常量入操作 10.2 通用操作 10.3 把局部变量压入 10.4 弹出顶部元素,将其赋给局部变量 10.5 wide指令 10.6 一个模拟:“Fibonacci Forever” 10.7 随书光盘 10.8 资源页 第11章 类型转换 11.1 转换操作码 11.2 一个模拟:“Conversion Diversion” 11.3 随书光盘 11.4 资源页 第12章 整数运算 12.1 二进制补码运算 12.2 Inner Int:揭示Java int类型内部性质 的applet 12.3 运算操作码 12.4 一个模拟:“Prime Time” 12.5 随书光盘 12.6 资源页 第13章 逻辑运算 13.1 逻辑操作码 13.2 一个模拟:“Logical Results” 13.3 随书光盘 13.4 资源页 第14章 浮点运算 14.1 浮点数 14.2 Inner Float:揭示Java float类型内部 性质的applet 14.3 浮点模式 14.3.1 浮点值集合 14.3.2 浮点值集的转换 14.3.3 相关规则的本质 14.4 浮点操作码 14.5 一个模拟:“Circle of Squares” 14.6 随书光盘 14.7 资源页 第15章 对象和数组 15.1 关于对象和数组的回顾 15.2 针对对象的操作码 15.3 针对数组的操作码 15.4 一个模拟:“Three—Dimensional Array” 15.5 随书光盘 15.6 资源页 第16章 控制流 16.1 条件分支 16.2 五条件分支 16.3 使用表的条件分支 16.4 一个模拟:“Saying Tomato” 16.5 随书光盘 16.6 资源页 第17章 异常 17.1 异常的抛出与捕获 17.2 异常表 17.3 一个模拟:“Play Ball!” 17.4 随书光盘 17.5 资源页 第18章 finally子句 18.1 微型子例程 18.2 不对称的调用和返回 18.3 一个模拟:“Hop Around” 18.4 随书光盘 18.5 资源页 第19章 方法的调用与返回 19.1 方法调用 19.1.1 Java方法的调用 19.1.2 本地方法的调用 19.2 方法调用的其他形式 19.3 指令invokespecial 19.3.1 指令invokespecial和[init]()方法 19.3.2 指令invokespecial和私有方法 19.3.3 指令invokespecial和super关键字 19.4 指令invokeinterface 19.5 指令的调用和速度 19.6 方法调用的实例 19.7 从方法中返回 19.8 随书光盘 19.9 资源页 第20章 线程同步 20.1 监视器 20.2 对象锁 20.3 指令集中对同步的支持 20.3.1 同步语句 20.3.2 同步方法 20.4 Object类中的协调支持 20.5 随书光盘 20.6 资源页 附录A 按操作码助记符排列的指令集 附录B 按功能排列的操作码助记符 附录C 按操作码字节值排列的操作码助

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值