JVM 基础知识

JVM

1. JVM 的位置

在操作系统上,可以看成是一个 软件,包含在 JRE 中

三种JVM

  • Sun 公司 HotSpot(使用最多)
  • BEA JRockit
  • IBM J9 VM

2. JVM 的体系结构

不会发生垃圾回收的区域:

JVM 调优的区域:

3. 类加载器

加载器类别

  • 虚拟机自带的加载器
  • 系统类(根)加载器(最终执行)
  • 扩展类加载器
  • 应用程序加载器

4. 双亲委派机制

采用这种机制,安全

AppClassLoder(应用程序加载器) --> PlatformClassLoder(扩展类加载器,JDK 1.9 之后) --> BootstrapClassLoder(系统类加载器)

执行过程:

  • 类加载器收到类加载的请求
  • 将这个请求向上委托给父类加载器去完成,一直向上委托,直到系统类加载器
  • 系统加载器检查是否能够加载当前这个类,能加载就结束,使用当前的加载器,否则,抛出异常,通知子加载器进行加载
  • 重复步骤 3
  • 如出现 null :说明 java 调用不到,因为底层是 c、c++ 写的

5.沙箱安全机制

Java 安全模型的核心就是 Java 沙箱(sandbox)

定义:沙箱是一个限制程序运行的环境,沙箱机制就是将 Java 代码限定在虚拟机特定的运行范围中,并且严格限制代码对贝蒂系统资源访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。

沙箱主要限制系统资源访问,那系统资源包括什么?

  • CPU
  • 内存
  • 文件系统
  • 网络

目前的安全机制实现,引入了域(Domain)的概念,虚拟机会把所有代码加载到不同的系统域和应用域。

组成沙箱的基本组件:

  • 字节码校验器(bytecode verifier)
  • 类加载器

类加载器采用的机制是双亲委派机模式

6. Native 关键字

凡是带了 native 关键字的,说明 java 的作用范围达不到了,会去调用底层 c 语言的库!

会进入本地方法栈,调用本地方法接口:JNI

JNI 作用:扩展 java 的使用,融合不同的编程语言为 Java 所用!最初:c、c++

它在内存区域中专门开辟了一块标记区域:Native Method Stack,登记 native 方法,在最终执行的时候,加载本地方法库中的方法通过 JNI

7. PC 寄存器

程序计数器(Program Counter Register)

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

8. 方法区

方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数、接口代码也在此定义,简单说,所有定义的方法的信息都保存在该区域,此区域属于共享区间:

静态变量(static)、常量(final)、类信息(构造方法、接口定义)、运行时的常量池 都存在方法区中,但是 实例变量存在堆内存中,和方法区无关

9. 栈

先进后出

栈内存,主管程序的运行,生命周期和线程同步

线程结束,栈内存也就释放啦,对于栈来说,不存在垃圾回收问题

栈溢出(可能是 递归调用 造成,循环调用,不断压栈)

存在栈里的内容:

  • 8 大基本类型
  • 对象引用
  • 实例的方法

栈运行原理:栈帧

栈满了:StackOverFlowError

10. 堆

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

类加载器读取了类文件后,把什么东西放到堆中?

  • 方法
  • 常量
  • 变量
  • 所有引用类型的真实对象

堆内存中细分为三个区域:

  • 新生区
  • 老年区
  • 元空间(永久区)

GC 垃圾回收,主要发生在 新生区 和 老年区

当一个对象经历了 15 次 GC 后,就会进入 老年区

假设内存满了,会发生 OOM(堆内存不够)

11. 新生区、老年区、元空间(JDK8之前为永久区)

永久区用来存放 JDK 自身携带的 Class 对象、Interface 元数据、存储的是 java 运行时的一些环境或类信息,这个区域不存在垃圾回收,关闭虚拟机会释放这个区域的内存

若一个启动类,加载了大量的第三方 jar 包,Tomcat 部署了太多的应用,大量动态生成的反射类,不断的被加载,直到内存满,就会出现 OOM

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

12. 堆内存调优

分析出现 OOM 的原因:

  • 尝试扩大堆内存空间看结果(默认情况下:分配的总内存是电脑内存的 1/4,而初始化的内存为:1/64)

  • 使用工具进行分析第几行代码出错

    内存快照分析工具,Jprofiler

    作用:可以分析 Dump 内存文件,快速定位内存泄漏,获得堆中的数据,获得大的对象

13. GC 常用算法

  • 引用计数法

  • 复制算法

    在幸存区中,from 和 to 会不停交换,谁空谁是 to,为了保证其中一个是空的,使用复制算法将其中一个复制到 to 中,再将另一个作为 to,保证 to 是空的

    好处:没有内存的碎片

    坏处:浪费了内存空间

  • 标记清除算法

    扫描对象,对活着的对象进行标记

    清楚没有标记的对象,进行删除

    优点:不会浪费内存空间

    缺点: 两次扫描,消耗了更多的时间。且又内存碎片产生

  • 标记压缩算法

    防止内存碎片产生,再次扫描,向一端移动存活的对象,但多了一个移动成本

14. GC 算法总结

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

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

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

没有最好的算法,只有最合适的算法

GC 为分代收集算法

​ 年轻代:

​ 存活率低:复制算法

​ 老年代:

​ 区域大,存活率高

​ 标记清除(内存碎片不是太多)+ 标记压缩混合 实现

Now is better than never
原文地址:https://www.cnblogs.com/alivinfer/p/14512353.html