JVM入门篇

JVM探究

  • 请你谈谈你对JVM的理解?java8虚拟机和之前的变化更新?
  • 什么是OOM,什么是栈溢出StackOverFlowError?怎么分析?
  • JVM的常用调优参数有哪些?
  • 内存快照如何抓取,怎么分析Dump文件?知道吗?
  • 谈谈JVM中,类加载器你的认识?

1.JVM的位置

  • JRE包含JVM(用C编写的)
    在这里插入图片描述

2.JVM的体系结构
在这里插入图片描述只有堆和方法区(特殊的堆)中会产生垃圾,所说的JVM调优百分之99都是在堆和方法区中进行调优!
3.类加载器
作用:加载Class文件~
在这里插入图片描述

1.启动类(根)加载器BootstrapClassLoader
2.扩展类加载器ExtClassLoader 
3.系统类加载器AppClassLoader
4.用户自定义类加载器CustomClassLoader

4.双亲委派机制

1.APP-->EXC-->BOOT(最终执行) 
类加载器收到类加载的请求
将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载(Boot)
启动加载器检查是否能够加载当前这个类,能加载就结束了使用当前加载器,否则,抛出异常,通知子加载器进行加载
重复上一个步骤

Class Not Found
null:java调用不到~C,C++
JAVA=C++--(去掉了指针和内存管理)

5.沙箱安全机制
沙箱安全机制
6.Native

 会进入本地方法栈
 调用本地方法本地接口    JNI
 JNI作用:扩展Java的使用,融合不同的编程语言为JAVA所用!
 它在内存区域专门开辟了一块标记区域:Native Method Stack 登记native方法
 只要是有native关键字的,说明java的作用范围达不到了,回去调用底层c语言的库!

7.PC寄存器

PC寄存器( PC register ):每个线程启动的时候,都会创建一个PC(Program Counter,程序计数器)寄存器。PC寄存器里保存有当前正在执行的JVM指令的地址。 每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。保存下一条将要执行的指令地址的寄存器是 :PC寄存器。PC寄存器的内容总是指向下一条将被执行指令的地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。

每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。

这块内存区域很小,它是当前线程所执行的字节码的行号指示器,字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。

如果执行的是一个Native方法,那这个计数器是空的。

8.方法区

存放static,final,Class,常量池

9.栈

栈:先进后出,后进先出:桶
队列:先进先出(FIFO:First Input First Output)
**喝多了吐就是栈,吃多了拉就是队列**
不存在垃圾回收问题
一旦线程结束,栈就Over
栈:8大基本类型+对象引用+实例的方法
栈运行原理:栈帧
栈满了:StackOverflowError
栈+堆+方法区:交互关系

在这里插入图片描述
10.三种JVM
SUN:HotSpot
BEA:JRockit
IBM:J9 VM

我们学习都是用·HotSpot·

11.堆

Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的。
类加载器读取了类文件后,一般会把什么东西放到堆中?类,方法,常量,保存我们所有引用类型的真实对象!
堆内存中还要细分为三个区域:新生区,老年区,永久区

在这里插入图片描述
GC垃圾回收,主要在伊甸园区和养老区
堆内存满了,会报OOM,java.lang.OutOfMemoryError: Java heap space

12.新生区,老年区
新生区

  • 类:诞生和成长的地方,甚至死亡;
  • 伊甸园区:所有的对象都是在伊甸园区new出来的
  • 幸存者区(0,1) 轻GC

老年区

  • 真理:经过研究,99%的对象都是临时对象!
  • 重GC

13.永久区
这个区域常驻内存的。用来存放JDK自身携带的Class对象。Interface元数据,存储的是JAVA运行时的一些环境或类信息~,这个区域不存在垃圾回收!关闭VM虚拟就会释放这个区域的内存!
一个启动类,加载了大量的第三方jar包。Tomcat部署了太多的应用,大量的动态生成的反射类。不断的被加载。直到内存满,就会出现OOM;

  1. jdk1.6之前:永久代,常量池是在方法区
  2. jdk1.7:永久代,但是慢慢的退化了,去永久代,常量池在堆中
  3. jdk1.8之后:无永久代,常量池在无空间

在这里插入图片描述
14.堆内存调优

long maxMemory = Runtime.getRuntime().maxMemory();//最大内存
long totalMemory = Runtime.getRuntime().totalMemory();//初始内存
默认情况下:分配的总内存是电脑内存的1/4,而初始化的内存是1/64
OOM错误解决:
1.尝试扩大堆内存查看结果
2.分析内存,看一下哪个地方出现了问题(专业工具)JPofiler

堆内存调参:-Xms1024m -Xmx1024m -XX:+PrintGCDetails
初始内存 最大内存 信息显示
在这里插入图片描述分析内存:IDEA安装JPofiler插件,安装JPofiler客户端
在这里插入图片描述OOM异常try,catch捕获不到

dump文件:在vm options中填写:-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
初始内存,最大内存,Dump哪个异常
在这里插入图片描述
dump文件会放到
在这里插入图片描述用JPofiler打开这个文件就可以进行分析!

堆中逻辑上存在元空间,物理上不存在元空间
15.GC
在这里插入图片描述

JVM在进行GC时,并不是对这三个区域统一回收,大部分回收在新生代
新生代,幸存区(form,to),老年区
GC两种类:轻GC(普通的GC)主要清理新生代,幸存区满清理幸存区,重GC(全局GC)全清

GC题目:

  • JVM的内存模型和分区~详细到每个区放什么?
    1.方法区:(被所有线程共享区域,用于存放已被虚拟机加载的类信息,常量,静态变量等数据)
    2.栈:(每个方法执行都会创建一个栈帧,用于存放局部变量表,操作栈,动态链接,方法出口等)
    3.本地方法栈:(本地方法栈是为执行本地方法(Native Method)服务的)
    4.程序计数器:(如果线程执行的是一个java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是nativa方法,这个计数器的值为空)

    5.堆:(存放对象实例)

  • 堆里面的分区有哪些?Eden,form,to,老年区

  • GC的算法有哪些?标记清除法,标记压缩,复制算法,引用计数器,怎么用的?
    引用计数法(给对象计数,不常用)
    在这里插入图片描述 复制算法
    幸存者中谁空谁是to
    当一个对象经历了15次GC,都还没有死,就会进入老年代(可以通过参数:“-XX:MaxTenuringThreshold=数字”设置经历多少次GC进行老年代)
    新生代主要用的是复制算法
    在这里插入图片描述在这里插入图片描述
    好处:没有内存的碎片
    坏处:浪费了内存空间~多了一半空间永远是空to。假设对象100%存活(极端情况)
    复制算法最佳使用场景:对象存活度较低的时候;新生区~
    标记清除算法
    在这里插入图片描述 优点:不需要额外的空间!
    缺点:两次扫描,严重浪费时间,会产生内存碎片
    标记压缩
    再优化:防止内存碎片产生
    在这里插入图片描述 标记清除压缩
    先标记几次
    再进行压缩

    总结
    内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)
    内存整齐度:复制算法=标记压缩算法>标记清除算法
    内存利用率:标记压缩算法=标记清除算法>复制算法
    没有最的算法,只有最合适的算法---->GC:分代收集算法
    新生代(年轻代):

    • 存活率低
    • 复制算法!

    老年代:

    • 区域大:存活率
    • 标记清除(内存碎片不是太多)+标记压缩混合实现
  • 轻GC和重GC什么时候发生?
    轻GC当如果 Eden(新生代) 空间占满了占满的时候,重GC当老年代空间不足的时候。

16.JMM
Java Memory Model的缩写
作用:缓存一致性协议,用于定义数据读写的规则(遵守,找到这个规则)。
在这里插入图片描述
JMM和底层实现原理
17.总结
百度加思维导图,多百度面试题

发布了21 篇原创文章 · 获赞 7 · 访问量 442

猜你喜欢

转载自blog.csdn.net/weixin_42998267/article/details/105174199
今日推荐