JVM知识梳理

本文详细梳理了JVM的运行图,包括方法区、PC寄存器、本地方法栈、栈、对象创建过程和内存分配。探讨了JDK1.8中为何替换永久代为元空间,并介绍了新生代、老年代、以及如何处理OOM问题。此外,文章还讨论了双亲委派机制、沙箱安全模型及其组件,最后简要提及了GC常用算法。
摘要由CSDN通过智能技术生成

JVM知识梳理

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

一、运行图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0gIyEXgb-1599444010989)(C:\Users\wangqun\AppData\Roaming\Typora\typora-user-images\image-20200906152739621.png)]

方法区

方法区:Method Area

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

​ 静态变量、常量(构造方法、接口定义),运行时常量池存在方法区中,但实例变量存在堆内存中,和方法区无关

运行时常量池:存放常量和符号引用(类和接口的全限定名、字段的名称和描述符、方法的名称和描述符)

OOM

PC寄存器

程序计数器:Program Counter Register

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

本地方法栈

本地方法栈:Native Method Stack

​ 它的具体做法是Native Method Stack中等级native方法,在(Excution Engine)执行引擎执行的时候加载Native Libraies 【本地库】

java栈:Stack

​ 栈 主要存放了编译期可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、对象引用 ( reference 类型 )

StackOverflow
OOM

创建一个对象的过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yjpVN6FL-1599444010995)(C:\Users\wangqun\AppData\Roaming\Typora\typora-user-images\image-20200906211030879.png)]

Native 类

  1. 凡是带了native关键字的,说明java达不到,回去调用底层C语言库
  2. 会进入本地方法栈
  3. 调用本地方法接口 Java Native Interface
  4. JNI作用:扩展java的使用 融合不同编程语言
  5. 在java创建初期想在C、C++横行的年代立足,所以开辟了本地方法栈

堆:Heap 易发生OOM
基于Java HotSpot(TM)

  • 一个JVM只有一个堆内存,堆内存大小可以调节。
  • 类加载器读取了类文件后,一般会把什么放入堆中?对象的实例、数组都在堆中分配内存
  • 三个区域
    • 新生区
    • 老年区
    • 永久区

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pIVmDpFy-1599444010999)(C:\Users\wangqun\AppData\Roaming\Typora\typora-user-images\image-20200906213208546.png)]

GC垃圾回收主要在Eden和Old区

假设OOM,堆内存不够! java.langOutOfMemoryError:java heap space

JDK1.8为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢?

  1. 整个永久代有一个 JVM 本身设置固定大小上限,无法进行调整,而元空间使用的是直接内存,受本机可用内存的限制,虽然元空间仍旧可能溢出,但是比原来出现的几率会更小。

当你元空间溢出时会得到如下错误: java.lang.OutOfMemoryError: MetaSpace

你可以使用 -XX:MaxMetaspaceSize 标志设置最大元空间大小,默认值为 unlimited,这意味着它只受系统内存的限制。-XX:MetaspaceSize 调整标志定义元空间的初始大小如果未指定此标志,则 Metaspace 将根据运行时的应用程序需求动态地重新调整大小。

  1. 元空间里面存放的是类的元数据,这样加载多少类的元数据就不由 MaxPermSize 控制了, 而由系统的实际可用空间来控制,这样能加载的类就更多了。
  2. 在 JDK8,合并 HotSpot 和 JRockit 的代码时, JRockit 从来没有一个叫永久代的东西, 合并之后就没有必要额外的设置这么一个永久代的地方了。

新生代

Eden:所有对象在这里诞生。

如果存满了Eden,进行轻量级GC,将Eden=>放入From survivor区或To survivor区

经过这次GC后,Eden区和"From"区已经被清空。这个时候,“From"和"To"会交换他们的角色”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,"To"区被填满之后,会将所有对象移动到老年代中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sgICcaod-1599444011003)(C:\Users\wangqun\AppData\Roaming\Typora\typora-user-images\image-20200906214755249.png)]

老年代

"To"区被填满之后,会将所有对象移动到老年代中。

永久代

这个区域存放jdk自带的Class对象,Interface元数据,存储的是java运行时的环境

不存在GC!关闭JVM时候会释放这个区域

  • jdk1.6 之前:永久代,常量池在方法区
  • jdk1.7:永久代,String池在堆中
  • jdk1.8:无永久代,常量池在元空间(直接内存)

在一个项目中如何查看OOM具体信息?

  • 能够看出代码第几行出错:内存快照工具,MAT,Jprofiler
  • Debug,一行行分析代码

MAT,JProfiler作用:

  • 分析Dump内存文件,快速定位内存泄漏
  • 获得堆中的数据
  • 获得大的对象…
#设置初始化内存分配大小1/64
-Xms1m 
#设置最大分配内存 默认1/4
-Xmx8m
//打印GC垃圾挥手
-XX:+PrintGCDetails
//OOM的Dump
-XX:+HeapDumpOnOutOfMemoryError

二、双亲委派机制

从上到下加载器分为

  • 启动类加载器(Boot)
  • 扩展类加载器(Ext)
  • 应用程序加载器(AppClassLoader)

加载过程

1、类加载器收到类加载的请求

2、将这个请求向上委托给符类加载器去完成,一直向上直到启动类加载器

3、启动类加载器检查是否能加载这个类,能加载就使用当前加载器,否则通知子加载器进行加载

4、重复步骤3

ClassNotFoundException

三、沙箱安全机制

​ Java安全模型的核心就是Java沙箱(sandbox),什么是沙箱?沙箱是一个限制程序运行的环境。沙箱机制就是将 Java 代码限定在虚拟机(JVM)特定的运行范围中,并且严格限制代码对本地系统资源访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。沙箱主要限制系统资源访问,那系统资源包括什么?——CPU、内存、文件系统、网络。不同级别的沙箱对这些资源访问的限制也可以不一样。

Java中的安全模型

在Java中将执行程序分成本地代码和远程代码两种,本地代码默认视为可信任的,而远程代码则被看作是不受信的。对于授信的本地代码,可以访问一切本地资源。而对于非授信的远程代码在早期的Java实现中,安全依赖于沙箱 (Sandbox) 机制。如下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4R1TFu9v-1599444011006)(C:\Users\wangqun\AppData\Roaming\Typora\typora-user-images\image-20200906155732843.png)]

但如此严格的安全机制也给程序的功能扩展带来障碍,比如当用户希望远程代码访问本地系统的文件时候,就无法实现。因此在后续的 Java1.1 版本中,针对安全机制做了改进,增加了安全策略,允许用户指定代码对本地资源的访问权限。如下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QhoiUDRh-1599444011008)(C:\Users\wangqun\AppData\Roaming\Typora\typora-user-images\image-20200906155749372.png)]

​ 当前最新的安全机制实现,则引入了域 (Domain) 的概念。虚拟机会把所有代码加载到不同的系统域和应用域,系统域部分专门负责与关键资源进行交互,而各个应用域部分则通过系统域的部分代理来对各种需要的资源进行访问。虚拟机中不同的受保护域 (Protected Domain),对应不一样的权限 (Permission)。存在于不同域中的类文件就具有了当前域的全部权限,如下图所示 最新的安全模型(jdk 1.6)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G7XAd2wr-1599444011009)(C:\Users\wangqun\AppData\Roaming\Typora\typora-user-images\image-20200906160623590.png)]

组成沙箱的基本组件

  • 字节码校验器(bytecode verifier):确保Java类文件遵循Java语言规范。这样可以帮助Java程序实现内存保护。但并不是所有的类文件都会经过字节码校验,比如核心类。

举例:记事本写java 进行编译 如果有错直接在编译阶段报错

  • 类装载器(class loader):其中类装载器在3个方面对Java沙箱起作用

    • 它防止恶意代码去干涉善意的代码:(操作不了C、C++写的代码)

    • 它守护了被信任的类库边界

    • 它将代码归入保护域,确定了代码可以进行哪些操作。

四、GC常用算法

详见: JavaGuide垃圾回收.

内存效率(时间复杂度):复制 > 标记清除 > 标记整理

内存整齐度:复制 = 标记整理 > 标记清除

内存利用率:标记整理 = 标记清除 > 复制

新生代:

  • 存活率低
  • 复制算法

老年代:

  • 区域大;存活
  • 标记清除 + 标记整理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值