项目总结笔记-JVM

1、什么是JVM

  1. Java虚拟机,包括类加载子系统,运行时数据区,执行引擎
  2. 常见的JVM虚拟机:hotstop,j9,Microsoft VM

如下是JVM的体系结构:
3. 类加载子系统会将class文件加载到jvm虚拟机中,同时将对应的数据放到运行时方法区中
4. 运行时方法区:放的是将要被运行的数据
5. 执行引擎:按照代码逻辑,去操作运行时方法区里的数据

2、 为什么Java是编译解释型语言

  1. Java先由编译器编译成class文件,(一次性)
  2. jvm加载class文件,由解释器逐行解释成OS认识的机器代码(逐行)

3、 jvm内存结构分为:堆,栈(jvm栈,本地方法栈),方法区,程序计数器

  1. 堆:线程共享的,存放对象的,gc主要回收堆中对象,堆分为新生代和老年代,新生代分为伊甸园区和幸存者区
    1. 伊甸园和survivor的比例:8.1.1
      2.新创建的对象都是放在堆中的伊甸园区
  2. 方法区:线程共享的,存放的有关类的一些信息,属性,方法,静态变量
  3. 程序计数器:线程私有的,放的是正在执行的线程指令地址,内存很小
  4. 栈(jvm栈):线程私有的,存的是函数运行时的临时变量
  5. 本地方法栈:线程私有的,保存的是native方法的信息,被native修饰的方法是操作系统的方法

4、Java内存模型JMM

  1. JMM其实就是一套规范,在多线程并发操作下,多核CPU处理器下,会有缓存一致性问题的出现(直接读写内存效率不高,就用到了高速缓存,运算结束后,把缓存中的数据刷新到主内存中),而且处理器为了效率就会指令重排序,(一般都是开辟空间,设置初始化值,然后指向内存空间),有可能顺序就发生变化了,这些都是问题,所以JMM就指定了一些规范来保证原子性,可见性和有序性
  2. 可以用sych,volatile,final来保证

5、为什么分代,为什么Eden和Surivior

  1. 分代的原因:如果不分代,会gc所有的对象,扫描整个堆,效率不高,如果分代,把所有新创建的朝生夕死的放到伊甸园区中,会先扫描这块内存,百分之80的对象都会被清除,把空间腾出来,gc的效率会更高
  2. 在新生代gc后一次后,还存活的对象会放到surivior幸存者区,(如果一次gc就将存活的对象放到老年区,因为老年代的gc是full gc会全部扫描,这样效率会降低)

6、jre和jvm的区别

  1. jvm运行可执行程序的
  2. jre运行时环境:包括jvm,还有核心类库String.class,Object.class
  3. jdk:Java开发工具包包括jre和编辑器,调试器,开发工具

7、 JVM的特性

  1. 移植性:在不同的系统上都可以运行java,因为jvm的存在
  2. 成熟性:发展了多年,体系很稳定,用的人也很多

8、什么是类加载?类加载的过程:(JVM类的生命周期)

  1. 类加载就是把类通过jvm虚拟机通过加载,验证,准备,解析,初始化的方式加载到内存
  2. 类加载的过程:
    1)加载:分三步:把class文件以二进制流的方式加载进来,在堆中生成对应的class文件
    2)验证:加载进来的class字节流是否符合标准,会不会威胁到jvm的安全
    3)准备:给class对象的静态变量开辟内存空间,设置初始化值
    4)解析:把赋值符号转为引用符号
    5)初始化:调用构造器执行Java代码的过程

9、类加载器

  1. 按照类加载器的顺序是为了让系统的类被优先加载

  1. 类加载器:通过全限定类名以二进制流的方式拿到一个类
  2. 类加载器是分层的:
    1)启动类加载器bootstrap:去加载核心类库,String.class,Object.class
    (getClassLoader为空,说明拿到的启动器是启动类加载器,使用c++来实现的)
    2)扩展类加载器Extension:去加载扩展类库,/etc/*
    3)系统类加载器Application ClassLoader:去应用中根据路径加载
    4)自定义类加载器customClassLoader:继承自classLoader

  1. 如何打破双亲委派机制:
    自定义类加载器,继承loadClass类,重写finalClass和loadClass方法(从特定位置拿到class文件)

10、双亲委派机制


  1. 类在被加载的是时候需要双亲委派机制
  2. 当类加载器需要加载一个类的时候,自己不会加载,会先将请求委派给父加载器,去父加载器的cache内存中寻找,当找到启动类加载器也找不到时,会按照加载器的顺序,依次的加载

  1. 父加载器不是继承的关系,而是组合的关系
  2. 为社么要有双亲委派机制:
    1)为了安全
    2)比如我自定义了一个java.lang.String覆盖了原来的String
    3)自定义的String被加载进来后,用户会使用自定义的,当用户使用String进行密码存储时,我就会偷偷的拿到用户的密码,这是不安全的
    4)使用双亲委派机制就不会出现这样的问题,一步步向上寻找,直到找到启动类加载器加载的核心类库,更加安全
  3. 如何打破双亲委派机制呢?
    1)自定义类加载器,继承classLoader类
    2)重写finalClass方法和loadClass方法
    3)findClass方法里通过全限定类名把class文件以二进制流的方式加载进来

11、为什么要有双亲委派机制

  1. 安全啊
  2. 比如我自定义了一个java.lang.String类覆盖调原来的String,会走custom自定义类加载器
  3. 当用户要设置密码时,就会用String来存储,用户也不知道我在底层做了什么操作
  4. 如果我可以通过邮件的方式拿到密码,这不就密码泄露了么

  1. 使用双亲委派机制就不会出现这种问题:
  2. 交给custom自定义类加载器时,会向上调用,调用booststrap时从扩展类里面找到了String类,然后就不会用自定义的,更加安全

12、类加载器的使用场景,你使用过么

  1. 自己加载一个类,要加载一个类的时候调用的是loadClass方法
    自定义类.class.getClassLoader().loadClass(“要加载进内存的类”)

13、判断是否可以被回收

  1. 可达性分析算法:根对象作为起点,向下寻找,被引用链引用着的对象是存活的对象,飘着的对象就可以被回收
  2. 根对象:
1. 本地方法区中常量和静态变量引用着的对象
2. 本地方法栈中引用的对象

在这里插入图片描述

14、Java中的垃圾回收算法

  1. 标记清除:先对可以回收的对象打上标记,然后清除;会有磁盘碎片的问题
  2. 标记整理:和标记清除是一样的,都是打上标记然后清除,然后把活着的对象全部向前移动,放到一起;没有了磁盘碎片的问题
  3. 复制/拷贝:把内存分成两个相等的空间,每次只使用一个空间,当空间用完时,把或者的对象复制到另一个空间上面,然后一次性清除当前空间;没有了磁盘碎片问题
  4. 分代回收算法:新生代用的是复制算法,老年代用的是标记整理算法;当对象的大小大于新生代的空间时,放到老年代存储,当新生代经历了几次垃圾回收依然存活,会放到老年代中

15、Java中的垃圾回收器

  1. 年轻代垃圾回收器:serial回收器,parallel new回收器,parallel scavenge回收器(都是复制算法,因为是新生代,大部分都被回收,复制的成本比较小)
1.servial:是单线程的当垃圾回收器工作时,其他线程不允许工作,所以用户体验不好
2. Parallel New :和servial是一样的需要stop the world,不过是多线程的
3. Parallel Scavenge:目标是达到一个可控的吞吐量
  1. 老年代回收器:serial old回收器,parallel old回收器,CMS回收器
5. serial old:一般和新生代回收器一起用
6. parallel old:一般和Parallel Scavenge一起用
7. CMS:基于标记清除实现的,有空间碎片,其目标是回收停顿时间达到无限小
  1. 介于新生代和老年代的回收器:G1

16、CMS

  1. CMS并发标记清除:目的是获得最短的停顿时间,并发:用户线程和gc线程在某些阶段同时执行,是基于标记清除算法的
  2. cms执行的四个步骤:
  1. 初始标记:标记gc跟对象直接连到的对象,这个对象不会很多,因此很快
  2. 并发标记:根据上一步的结果,遍历执行链上的所有对象
  3. 重新标记:重新标记一次,因为并发标记时,没有暂停用户线程,可能产生新的垃圾
  4. 并发清除:清除被标记的对象
  1. cms出现的问题
  1. 并发虽然不会暂停用户线程,但是会抢占一部分线程,造成用户线程变慢,当cpu比较少时,对用户线程的性能影响大
  2. 无法清除浮动垃圾:在并发清理时,用户线程还在执行,还会制造新的垃圾
  3. 并发失败:因为gc线程和用户线程同时执行,所以要预留一部分内存空间给用户线程,回收垃圾用
  4. 内存碎片问题:cms使用标记清除算法,就会有空间碎片的出现

17、G1的回收过程

  1. cms可以并发标记和并发处理,但是他依然有stop the world这一步骤,所以就出现了G1,目的是降低stop the world的停顿时间,G1可以回收新生代和老年代垃圾,不会分代,直接将内存划分为大小相等的region区域

18、Java对象创建过程

  1. Java虚拟机识别到new这条指令,去常量池中看能不能找到这个类的符号引用,看这个符号引用的类是否已经被加载,检查,准备,解析,初始化,如果没有执行加载的过程
  2. 给对象开辟内存空间
  1. 指针标记法:内存中使用过的站一边,空闲的站一边,用指针标记这中间的位置,指针移动的大小就是对象的内存大小
  2. 空闲列表法:内存中用过的和空闲的是混杂在一起的,JVM中维护了一个空闲列表,找一个合适的空间分配给对象实例
  1. 给对象的内存空间设置初始化值
  2. JVM会把对象的哈希值,元数据信息,gc分代年龄设置到对象头中
  3. 最后调用init初始化方法初始化
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值