JVM,DVM虚拟机

允我心安 提交于 2020-03-09 00:44:59

Java虚拟机–JVM,类加载器,双亲委派

https://www.iteye.com/blog/welcome66-2216572

1、JVM(Java Virtual Machine),java虚拟机

JVM就是虚拟出来的计算机,有自己完善的架构,处理器,堆栈,寄存器,指令系统。使用jvm就是为了支持与操作系统无关,java跨平台的原理,因为java代码都在这上运行,.java文件通过javac命令编译后生成.class字节码文件,JVM的java解释器负责把.class字节码文件转化为特定的机器码文件运行。

1.进程级别,守护线程和非守护线程(用户线程)
守护线程:后台线程,为前台线程提供便利服务,比如GC线程。不要在守护线程中执行业务逻辑操作(比如对数据的读写等)。
非守护线程:前台线程

设置守护线程:public final void setDaemon(boolean on)
判断守护线程:public final boolean isDaemon()

2.生命周期:
启动:启动java是开启,起点是public static void main
运行:main起点,两种线程:守护线程(JVM),非守护线程(JAVA),java也可以创建自己的守护线程
消亡:程序终止则退出,也可以用System.exit或Runtime类来退出

3.体系结构
类装载器(ClassLoader)–用来装载.class文件
执行引擎(执行字节码,执行本地文件)
运行时数据区(方法区,堆,java栈,PC寄存器,本地方法栈)

2. ClassLoader类加载器

https://blog.csdn.net/poorcoder_/article/details/80258725
1 JVM整个类加载过程的步骤:
①.装载:二进制字节码加载到JVM,通过三个标识:类名,类所在的包名和ClassLoader实例ID
②.链接:1.对二进制字节码的格式进行校验初始化装载类中的静态变量以及解析类中调用的接口、类; 2.完成校验后,初始化静态变量赋默认值;3.最后对所用的属性,方法进行验证,确保存在,具有应有的权限。
③.初始化
执行静态代码块,构造器代码,静态属性初始化,类变量(static)会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
四纵情况会被触发执行:new,反射,子类调用初始化,jvm指定初始化类
4.2. JVM整个类加载顺序:
①java类装载器包括:启动类装载器(JVM的一部分) 和 用户自定义装载器(JAVA的一部分,必须是ClassLoader的子类)
②装载顺序:JVM启动时,由bootstrap 向User-Defined方向加载类;应用进行ClassLoader时,由User-Defined向Bootstrap方向查找并加载类

3 双亲委派

背景:判定两个类是否为同一个类,判定原则是是否由一个类加载器加载;所以导致多个类加载器可能会导致有多个不同的类,比如Object类如果有其他类加载器加载,就会导致有多个Object类,无法保证java的行为执行,会混乱。所以引入双亲委派:加载类的时候,先去让父类加载(顶层父类是启动类加载器,所以顶层都会走加载的方法)。如果父类不能加载,则传给子类加载,父子关系不是继承,而是组合(Composition)。带有优先级。

  • 启动类加载类 Bootstrap,顶级加载器,加载java核心API,用navive code(特定于处理器的机器码的代码)创建
  • 扩展类加载器 Extension ,被java变量所制定的类库,开发者可以直接使用
  • 应用程序类加载器 Application ,加载类路径ClassPath上指定的类库,开发者可以直接使用,如果没有自定义类加载器,那么这就是默认的。
    在这里插入图片描述
    在这里插入图片描述
    ClassLoader重要方法:
  • loadClass(),ClassLoader自己实现的,JDK1.2后用户可以直接调用,代码逻辑就是双亲委派的体现,先去缓存找,找得到直接返回,找不到去父加载器,父亲没有去启动加载器,最后都没有去findClass
  • findClass,直接抛出ClassNotFound,所以自己可以重写,来让其实现类的加载,这样也就保证自定义的加载器符合双亲委派模型。
  • defineClass,byte字节流解析成JVM能够识别的Class对象(ClassLoader中有这个方法逻辑),也可以通过其他方式,比如网络接收字节码转化为byte,再转化为Class,通常匹配findClass使用,自定义的时候直接覆盖findClass,然后去取得字节流,在使用defineClass生成Class对象。
  • resolveClass() ,loadClass中被调用,连接指定java类,主要是对字节码进行验证,

类加载器命名空间
不同的类加载器在虚拟机中处于不同的命名空间下,他们不可见
但是,例子:自己写的A类有AppClassLoader加载器加载,List由Bootstrap加载器加载,A访问List,先去自己的AppClassLoader,找不到,再去找父类,一直到顶层Bootstrap 找到List类

4 自定义ClassLoader

  • 背景,可以对class文件进行加密和解密。
  • 实现方式
    重写findClass方法,

5. java的堆内存情况,性能分析工具

5.1 java内存模型

在这里插入图片描述

  • 主内存就是硬件内存,本地内存是抽象内存:缓存,写缓存区,寄存器

  • volatile修饰之后,本地内存可以达到互相可见,原理是会把本地内存刷新到主内存上。

  • java内存同步的八种操作
    作用于主内存(Main Memory):
    lock,unlock,read(主–》工作,之后进行load),write(store之前的操作,工作–》主)
    作用于工作内存:
    load(read之后的操作,主–》工作的变量副本),use(工作–》执行),assign(执行–》工作变量),store(工作–》主,之后进行write)

  • 规则
    顺序操作,必须全顺序
    不允许(read,load )或者 (Store,Write)单独出现
    不允许线程丢弃assign,即变量改变后必须把数据同步到主内存
    没有进行assign操作,不允许同步到主内存
    允许单一线程多lock,但需要多unlock,成对出现

在这里插入图片描述

6. Java垃圾回收(GC)机制详解

https://blog.csdn.net/woainimax/article/details/75560973?ops_request_misc=%7B%22request%5Fid%22%3A%22158322800019724845059314%22%2C%22scm%22%3A%2220140713.130056874…%22%7D&request_id=158322800019724845059314&biz_id=0&utm_source=distribute.pc_search_result.none-task

  • 原理:没有引用的对象,内存将变为垃圾
  • 对象的回收:1.没有引用,引用为null,引用对象转移,2. 弱引用
  • 方法区的垃圾回收:1. 废弃常量。2. 无用的类。
6.1 强制系统垃圾回收方式
  • System.gc();
  • Runtime.getRuntime().gc();
  • 备注:并不是立刻回收,也会做一些算法进行加权,使垃圾回收容易发生,提早发生,回收较多
6.2 finalize

是方法名,在Object类中定义,所以所有的类都继承了他
在垃圾回收机制清除内存前做必要的清理工作
只能运行一次
用于一些不容易控制,而且非常重要的资源释放
程序本身释放为主,finalize函数释放为辅,双保险管理

6.3 判定回收(jvm怎么确定哪些对象应该进行回收)

1.引用计数,来判断一个对象是否可以被回收,但是循环指向就不会回收
2. 可达性分析,关系图,节点,引用链,判定是否可达
在这里插入图片描述

6.4 jvm会在什么时候进行回收
  1. 会在cpu空闲的时候自动进行回收
  2. 在堆内存存储满了之后
  3. 主动调用System.gc()后尝试进行回收
6.5 垃圾回收算法(如何回收)–四个算法
  1. Mark-Sweep(标记-清除)算法:最基础,容易实现,会产生大量的不连续内存
  2. Copying(复制)算法:平均分为两块内存,只使用一块,然后用完之后把依旧存活的对象转移到另一块,原来区域清理。特点,简单不会产生碎片,但是牺牲内存
  3. Mark-Compact(标记-整理)算法:在标记清除算法上添加了整理,使其没有内存碎片,
  4. Generational Collection(分代收集)算法:目前大部分JVM的垃圾收集器采用的算法,核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域,一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation)
  • Generational Collection(分代收集)算法详解
    新生代,频繁大量回收,通常使用时间占优的GC,需要复制的操作较少,所以Copying算法。
    老年代,少量被回收,通常使用善于处理大空间的GC,因为老年代的空间大,GC频率低引用,使用Mark-Compact算法。

  • 引用分为强引用、软引用、弱引用、虚引用4种,这4种引用强度依次减弱。
    1、强引用
    代码中普遍存在的类似"Object obj = new Object()"这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
    2、软引用
    描述有些还有用但并非必需的对象。在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围,进行二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。Java中的类SoftReference表示软引用。(网站缓存)
    3、弱引用
    描述非必需对象。被弱引用关联的对象只能生存到下一次垃圾回收之前,垃圾收集器工作之后,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。Java中的类WeakReference表示弱引用。(handler内存泄露,bitmap缓存)
    4、虚引用
    这个引用存在的唯一目的就是在这个对象被收集器回收时收到一个系统通知,被虚引用关联的对象,和其生存时间完全没关系。Java中的类PhantomReference表示虚引用。

Android虚拟机–DVM(Dalvik VM)

JVM标准执行的是.class的字节码(bytecode ),
而DVM执行的是其专有的(.dex)执行文件。
使用.dex格式原因:
去除掉.class的陈余信息,所有的.class整合到.dex文件中
减少了文件内存和I/O操作,提高查找速度
增加了对新的操作码的支持

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!