# JVM

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

# JVM位置

  • 操作系统上的(运行虚拟机-)

# JVM的体系结构

# 类加载器

作用:加载class文件

  1. ClassLoader 类加载器 加载,验证,准备,解析,初始化,使用,销毁
  • 虚拟机自带的加载器
  • 启动类(根)加载器
  • 扩展类记载器
  • 应用程序加载器 null C 写的

# 双亲委派机制

保证安全

  1. APP->EXC->BOOT
  2. 向上委托 能加载就结束 否则 通知子加载器加载

# 沙箱安全机制

限制程序运行的环境,以前默认远程代码是不安全的

  • 字节码校验器
  • 类装载器
  • 存取控制器 存取权限
  • 安全控制器 权限控制
  • 安全软件包 keytools https

# Native

调用底层C语言的库,会进入本地方法栈,调用JNI,本地方法接口,扩展Java的使用,融合不同的编程语言。

  • 融合C和C++,必须要有调用C和C++的程序,想要立足
  • 内存区域中专门开辟了一块标记区域,登记native方法
  • 在最终执行的时候,加载本地方法库中的方法 通过JNI

打印机

# PC寄存器

每一个线程都有一个程序计数器,线程私有,就是一个指针,指向方法区的方法字节码,在执行引擎读取下一条指令,非常小的内存空间,几乎可以忽略不计。

# 方法区

线程共享,构造函数,接口,定义方法的信息

静态变量,常量,类信息,运行时的常量池存在方法区中,但是实例变量存在堆内存中

java 1.7 1.8 常量池在堆

#

数据结构,先进先出。栈内存,主管程序的运行,生命周期和线程同步

两个方法互相调用,就会发生栈溢出

线程结束,栈内存也就是释放

对于栈来说不存在垃圾回收。

8大基本数据类型+对象引用+实例的方法

  • 方法索引(index)
  • 输入输出参数()
  • 本地变量
  • 引用
  • 父帧
  • 子帧

# 三种JVM

  • Sun公司 HotSpot
  • BEA JRockit 适合军事通信和
  • IBM J9VM 跟硬件绑定

#

一个JVM,只有一个堆内存,堆内存的大小是可以调节的

类加载器读取了类文件后,一般会把什么放入堆中

类的实例对象,方法,常量1.8,变量

# 新生区 老年群 永久区

新生区

  • 伊甸园(Eden Space)
  • 幸存0区
  • 幸存1区

养老区

永久存储区(jdk8 元空间)

GC垃圾回收,主要在伊甸园区和养老区

内存满了 OOM 堆内存不够

新生区

  • 一个类:诞生和成长的地方。甚至死亡
  • 伊甸园区 new 对象的 满了 轻GC
  • 幸存区的也满了就会进行重GC,进入养老

永久区(用来存放jdk自身存在的Class对象,java运行时的一些环境和类信息)不存在垃圾回收,关闭虚拟机,释放内存,

元空间逻辑上存在,物理上不存在·

  1. 一个启动类加载了大量的第三方Jar包
  2. Tomcat部署了太多的应用
  3. 大量动态生成的反射类,不断被加载
  • jdk1.6 永久代 常量池在方法区中
  • jdk1.7 永久代 退化了 去永久代 常量池在堆中
  • jdk1.8 无永久代,常量池在元空间(元空间 ),元空间里面有方法区和常量池

# 字符串常量池在堆,运行时常量池在元空间

long max = Runtime.getRuntime().maxMemory();// 试图使用的虚拟机内存
long total = Runtime.getRuntime().totalMemory();// 返回jvm的初始化总内存

# 堆内存调优

默认分配的总内存是 电脑内存的4/1

初始化的内存 是64/1

-Xms1024m -Xmx1024m -XX:+PrintGCDetails
// -Xms 初始化 默认 1/64
// -Xmx 设置最大分配内存,默认 1/4
// 能够看到第几行代码出错,内存快照分析工具,MAT,Jprofiler
// 分析Dump文件,快速定位内存泄漏问题
// 获得堆中的数据
// 获得大的对象
// Dump 文件
-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
// 最大任期时间 通过这个参数可以设定进入老年代的时间
-XX: MaxTenuringThreshold=5

# GC垃圾回收

  • 轻GC和重GC
  • 谁空谁是to
  • 15次GC没有死进入养老区

引用计数法:对象的引用次数,计数器本身也会有消耗。

复制算法:年轻代,有一个要是空的,(对象存活度较低)

  • 好处:没有内存的碎片
  • 坏处:浪费了内存空间

标记清除法:扫描这些对象,对活着的进行标记。对没有标记的对象进行清除。

  • 好处:不需要额外的空间!
  • 坏处: 两次扫描,严重浪费时间,会产生内存碎片。

标记清除压缩算法: 压缩防止内存碎片产生,再次扫描,向一端移动存活的对象,多了一个移动成本

分代收集算法:是根据对象的生命周期,把内存作分代,然后在分配对象的时候,不同生命周期的对象放在不同的代里面,不同的代上使用合适的回收算法进行回收

# JMM(抽象的概念)

javaMemoryModel

java内存模型

缓存一致性协议,用于定义数据读写的规则

JMM定义了线程工作内存 和主内存之间的抽象关系,线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存.

volatile保证共享对象的可见性,synchronized

happens-before规则,happens-before仅仅要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前 。

# 总结

内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)

内存整齐度: 复制算法 = 标记压缩算法 >标记清除算法

内存利用率:标记压缩算法 = 标记清除算法 > 复制算法

没有最好的算法,但是只有最合适的。

分代收集算法:

年轻代:

  • 存活率低
  • 复制算法!

老年代:

  • 区域大:存活率高
  • 标记清除(内存碎片不是很多)加标记压缩混合 实现
更新时间: 2024年11月5日星期二下午4点33分