Android进阶解密读书笔记(十)——Java虚拟机
一、Java虚拟机的执行流程
Java虚拟机执行流程分为两大部分:编译时环境和运行时环境,当一个Java文件经过Java编译器编译后会生成class文件,这个class文件会由Java虚拟机来进行处理
Java虚拟机与Java语言没有什么必然的联系,它只与特定的二进制文件:Class文件有关;因此无论任何语言只要能编译成Class文件就可以被Java虚拟机来处理
二、Java虚拟机结构
Java虚拟机结构包括运行时数据区域、执行引擎、本地库接口和本地方法,其中类加载子系统并不属于Java虚拟机的内部结构1
1、Class文件格式
java 文件被编译后生成了Class文件,这种二进制格式的文件不依赖于特定的硬件和操作系统。每一个Class文件中都对应着唯一的类或者接口定义信息,但是类或者接口并不一定定义在文件中,比如类和接口可以通过类加载器来直接生成
2、类的生命周期
一个Java文件被加载到Java虚拟机内存中到从内存中卸载的过程被称为类的生命周期。类的生命周期包括的阶段分别是:加载、链接、初始化、使用和卸载,其中链接包括了三个阶段:验证、准备和解析。各个阶段所做的工作如下:
- 加载:查找并加载class文件
- 链接:包括验证准备和解析
验证:确保被导入类型的正确性
准备:为类的静态字段分配字段,并用默认值初始化这些字段
解析:虚拟机将常量池内的符号引用替换为直接引用 - 初始化:将类变量初始化为正确的初始值
根据《深入理解Java虚拟机》的描述,加载阶段(不是类的加载)主要做了3件事情
- 根据特定名称查找类或接口类型的二进制字节流
- 将这个二进制字节流所代表的静态存储结果转化为方法区的运行时数据结构
- 在内存中生成一个代表这个类的 java.lang.class 对象,作为方法区这个类的各种数据结构的访问入口
3、类加载子系统
类加载子系统通过多种类加载器来查找和加载 Class 文件到 Java 虚拟机中,Java虚拟机有两种类加载器:系统加载器和自定义加载器,其中系统加载器包括以下三种:
- Bootstrap ClassLoader(引导类加载器)
用 C/C++ 代码实现的加载器,用于家啊在指定的JDK核心类库,它用来加载以下目录中的类库:$JAVA_HOME/jre/lib 目录 -Xbootclasspath参数指定的目录
Java虚拟机的启动就是通过引导类记载器创建一个初始类来完成的。由于类加载器是使用平台相关的底层C/C++语言实现的,所以该加载器不能够被 JAVA 代码访问到,但是我们可以查询某个类是否被引导类加载器加载过
Extension ClassLoader(拓展类加载器)
用于加载 Java 的拓展类,提供除了系统类之外的额外功能。它用来加载以下目录中的类库:加载 $JAVA_HOME/jre/lib/ext 目录 系统属性 java.ext.dir 所指定的目录
Application ClassLoader(应用程序类加载器)
又称作 System ClassLoader(系统类加载器),这是因为这个类加载器可以通过 ClassLoader 的 getSystemClassLoader 方法获取到。它用来加载以下目录中的类库
* 当前应用程序 Classpath 目录 * 系统属性 java.class.path 指定的目录
除了系统加载器还有自定义加载器,它是通过继承 java.lang.ClassLoader 类的方式来实现自己的类加载器的
4、运行时数据区域
- 程序计数器(Program Counter Register)
程序计数器的作用是保证程序能够连续地执行下去,处理器必须具有某些手段来确定下一条指令的地址
程序计数器也叫做 PC 寄存器,是一块较小的内存空间,Java 虚拟机的多线程是通过轮流切换并分配处理器执行时间的方式来实现的,为了线程切换后能够恢复到正确的执行位置,每个线程都会有一个独立的程序计数器 - Java 虚拟机栈
每一条 Java 虚拟机线程都有一个线程私有的 Java 虚拟机栈。他的生命周期与线程相同,与线程是同时创建的。
当线程调用一个 Java 方法时,虚拟机压入一个新的栈帧到该线程的 Java 虚拟机中,在该方法执行完成后,这个栈帧就从 Java 虚拟机栈中弹出;平常所说的栈内存(Stack)指的就是 Java 虚拟机栈 - 本地方法栈
Java 虚拟机实现可能会用到 C Stacks 来支持 Native 语言,这个 C Stacks 就是本地方法栈(Native Method Stack) - Java 堆(Java Heap)
是被所有线程共享的运行时内存区域,用来存放对象实例,这些对象被垃圾收集器管理 - 方法区(Method Area)
是被所有线程共享的运行时内存区域,用来存储已经被 Java 虚拟机加载的类的结构信息,包括运行时常量池、字段和方法信息,静态变量等数据 - 运行时常量池(Runtime Constant Pool)
是方法区的一部分,用来存放编译时期生成的字面量和符号引用
三、对象的创建
通过 new 指令来完成一个对象的创建,当虚拟机接收到一个 new 指令时,它会做出如下操作:
- 判断对象对应类是否加载、链接和初始化
- 为对象分配内存
类加载完成后,接着会在 Java 堆中划分一块内存分配给对象,内存分配是根据 Java 堆是否规整,有两种方式:① 指针碰撞:如果 Java 堆的内存是规整的,即所有用过的内存放在一边,而空闲的内存放在另一边。分配内存时将位于中间的指针指示器向空闲的内存移动一段与对象大小相等的巨鹿,这样便完成分配
② 空闲列表:如果 Java 堆的内存是不规整的,则需要由虚拟机维护一个列表来记录那些内存是可用的,这样在分配的时候可以从列表中查询到足够大的内存分配给对象,并在分配后更新列表记录
- 处理并发安全问题
- 初始化分到的内存空间
将分配到的内存,除了对象头外都初始化为零值 - 设置对象的对象头
- 执行 init 方法进行初始化
四、对象的堆内存布局
以 HotSpot 虚拟机为例,对象在堆内存的布局分为三个区域,分别是对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)
- 对象头:包括两部分信息,分别是Mark World和元数据指针;Mark World 用于存储对象运行时的数据,比如 HashCode、锁状态标志、GC分代年龄、线程持有的锁等;元数据指针用于指向方法区中的目标类的元数据,通过元数据可以确定对象的具体类型
- 实例数据:用于存储对象中的各种类型的字段信息
- 对齐填充:对齐填充不一定存在,起到了占位符的作用,没有特别的含义
五、垃圾标记算法
垃圾收集器(GarbageCollection)通常被称作 GC。GC主要做了两个工作,一个是内存的划分和分配;另一个是对垃圾进行回收。
Java 堆作为 GC 主要管理的区域,被分为新生代和老年代,再细一点新生代又可以划分为Eden空间、From Survivor空间、To Survivor空间,在对垃圾进行回收之前,GC要先标记出垃圾,目前有两种垃圾标记算法,分别是引用计数法和根搜索算法,这两个算法都和引用有些关联
1、Java 中的引用
- 强引用:新建一个对象时就创建了一个具有强引用的对象,GC绝对不会回收它,JavaVM 宁愿抛出 OutOfMemoryError 异常
- 软引用:当内存不够时会回收这些对象的内存,Java提供了 SoftReference 类来实现软引用
- 弱引用:GC 一旦发现只具有弱引用的对象,不管内存是否足够都会回收它的内存,使用 WeakReference 类来实现
- 虚引用:虚引用并不会决定对象的生命周期,如果一个对象仅持有虚引用,这就和没有任何引用一样,在任何时候都可能被GC回收,一个只具有虚引用的对象,被垃圾收集器回收时会受到一个系统通知,这也是虚引用的主要作用,使用 PhantomReference 类来实现
2、引用计数算法
每个对象都有一个引用计数器,当对象在某处被引用的时候,他的引用计数器就+1,引用失效时就-1;当引用计数器中的值变为0,则该对象就不能被使用,变成了垃圾。
目前主流的Java虚拟机没有选择引用计数法来为垃圾标记,主要原因是引用计数算法没有解决对象之间相互训话引用的问题
3、根搜索算法
选定一些对象作为GCRoots,并组成根对象集合,然后以这些GCRoots的对象作为起始点,向下搜索,如果目标对象到GCRoots是连接着的,则称为该目标对象是可达的,如果目标对象不可达则说明目标对象是可以被回收的对象
在Java中可以作为GCRoots的对象主要有以下几种:
- Java栈中引用的对象
- 本地方法栈中JNI引用的对象
- 方法区中运行时常量池引用的对象
- 方法区中静态属性引用的对象
- 运行中的线程
- 由引导类加载器加载的对象
- GC控制的对象
常用的GC算法:标记——清除算法、复制算法、标记——压缩算法、分代收集算法
六、Java对象在虚拟机中的生命周期(7个阶段)
1、创建阶段(Created)
具体步骤为:
- 为对象分配存储空间
- 构造对象
- 从超类到子类堆 static 成员初始化
- 递归调用超类的构造方法
- 调用子类的构造方法
2、应用阶段(In Use)
当对象被创建并分配给变量赋值时,状态就切换到了应用阶段
3、不可见阶段(Invisible)
在程序中找不到对象的任何强引用,在该阶段,对象仍可能被特殊的强引用GCRoot持有着
4、不可达阶段(Unreachable)
在程序中找不到对象的任何强引用,并且垃圾收集器发现对象不可达
5、收集阶段(Collected)
垃圾收集器已经发现对象不可达,并且GC已经准备好要对该对象的内存空间进行重新分配,这个时候如果该对象重写了 finalize 方法则会调用该方法
6、终结阶段(Finalized)
在对象执行完 finalize 方法后仍处于不可达状态时,会进入该阶段,并等待 GC 回收该对象空间
7、对象空间重新分配阶段(Deallocated)
当GC对象的内存空间进行回收或再分配时,这个对象就会彻底消失
Android进阶解密读书笔记(十)——Java虚拟机相关推荐
- Android进阶之光 读书笔记
第一章, Android 5.6.7新特性 1.RecycleView的自定义分割线 public class DividerItemDecoration extends RecycleView.It ...
- Android进阶之光读书笔记——第一章:Android新特性
第一章 Android新特性 主要讲了一些Android 5.0.6.0.7.0新特性 1.1 Android 5.0新特性 Android 5.0 Lollipop是2014年10月发布的,那时候我 ...
- Android进阶之光读书笔记——第三章:View体系与自定义View
第三章 View体系与自定义View 本章将介绍Android中十分重要的View,在多本书中View是必讲的一节,Android群英传就讲了不少的View的知识,那么在这里我们再去复习一遍吧 3.1 ...
- 《Android 音视频开发》《 Android 进阶解密》 书籍赠送
今年听了一年的 "Android不行了..." 之类的谣言,这不都年底了嘛,也没看见哪个公司停止了安卓开发需求. 最近又出现了很多关于"互联网寒冬..."之类的 ...
- 获取虚拟机的唯一标识_JVM笔记:Java虚拟机的类加载机制(附详细思维导图)...
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 类加载的流程 类从被加载到虚拟机内存中开始, ...
- 学习笔记【Java 虚拟机②】垃圾回收
若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 总目录 学习笔记[Java 虚拟机①]内存结构 学习笔记[Java 虚拟机②]垃圾回收 学习笔记[Java ...
- 图解HTTP读书笔记(十)
图解HTTP读书笔记(十) Web的攻击技术 HTTP协议本身并不存在安全性问题,因此协议本身几乎不会成为攻击对象.应用HTTP协议的服务器和客户端,以及运行在服务器上的Web应用资源才是攻击目标. ...
- 第一行代码Android第二章读书笔记
第一行代码Android第二章读书笔记 Activity 1.1 手动创建活动 1.2 Toast和Menu/销毁活动 Intent 2.1 显示/隐式 2.2 传递/返回数据 活动的生命周期 3.1 ...
- 主成分分析碎石图_ISLR读书笔记十九:主成分分析(PCA)
本文使用 Zhihu On VSCode 创作并发布 前面写的一些统计学习方法都是属于监督学习(supervised learning),这篇主成分分析(principal components an ...
最新文章
- linux lvm 调整分区大小,linux调整lvm分区大小(/home分区过大,/root分区过小)
- HDFS基本概念和特性的详情了解及优缺点
- 实现一个简单的前端水印
- 一步一步写算法(之字符串查找 中篇)
- Comparable与Comparator异同
- spring quartz执行两次问题
- ios是否安装了某应用
- 移动设备尺寸规范汇总(转)
- 下载图片的java工具类_ftputil 下载图片工具类
- python实现人民币大小写转换
- 虚拟机安装银河麒麟V10系统
- linux无法连接共享文件夹,linux下samba服务器共享文件windows无法访问
- 台式机装苹果系统_AMD台式机装苹果系统!!
- URP——后期处理特效——通道混合器Channel Mixer
- 二叉树的左视图和右视图
- 学习排序 Learning to Rank:从 pointwise 和 pairwise 到 listwise,经典模型与优缺点
- 数据采集程序-----直播间
- iOS 手机淘宝 自动创建一个人的群聊 实现源码 hook 代码源码
- win10内存占用率过高怎么办_DNF:WIN10玩DNF卡顿,内存占用过高的解决方法
- intouch中DA server的配置文件