[笔记]-JVM入门学习

13 篇文章 1 订阅

typora-root-url: ./


JVM学习前言

学习视频地址

  • 谈谈你对JVM的理解;Java8虚拟机与之前等待变化
  • OOM,栈溢出StackOverFlowError,如何分析
  • JVM的常用调优参数
  • 内存快照如何抓取,如何分析Dump文件
  • JVM中类加载器

JVM体系结构

在这里插入图片描述

更加详细的结构为:

类加载器

作用:加载.class文件

流程大致为:

分类:按照从低到高可分为:

  • 虚拟机加载器(引导类加载器)
  • 扩展类加载器
  • 系统类(启动类)加载器
  • 应用类加载器

双亲委派机制

某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

全都找不到报: Class Not Found

沙箱安全机制

在早期的jvm中,对于本地代码信任,可以直接运行,而远程代码是放置在沙箱中运行,限制对系统资源的访问。

此后增加了 安全策略,可以在给定一些权限后对本地资源访问。

然后又增加了 代码签名,按照用户的安全策略设定,又类加载器来加载道虚拟机中权限不同的运行空间运行

现在的安全机制引入 的概念,虚拟机将所有的代加载不同的系统域和应用域中,系统域负责关键资源,应用域通过系统域的部分代理来操作资源。不同的受保护域对应不同的权限。

组成沙箱的基本条件:

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

  • 类装载器: 类装载器在3个地方对Java沙箱起作用:

    • 放置恶意代码干涉善意代码

    • 守护被信任的类库边界

    • 将代码归入保护域

      虚拟机为不同的类加载器提供不同的命名空间,有唯一的标识,且由Java虚拟机的每一个类装载器维护,相互不可见

​ 类加载器使用的是双亲委派机制:

  • 从最内层jvm自带类加载器开始加载,外层恶意同名类得不到加载从而无法使用

  • 由于严格通过包来区分访问域,外层恶意的类通过内置代码也无法获得权限访问道内层类,破坏代码自然无法生效

  • 存取控制器: 存取控制器可以控制核心API对操作系统的存取权限,控制的策略可以通过用户指定

  • 安全管理器:是核心API和操作系统之间的主要接口。实现权限控制,比存取控制器优先级高

  • 安全软件包java.security 下的类和扩展包下的类,允许用户为自己的应用增加新的安全特性:

    • 安全提供者
    • 消息摘要
    • 数字签名
    • 加密
    • 鉴别

Native

native:凡是使用 native 关键字修饰的,说明Java的作用范围达不到,会调用底层C/C++的库文件等等

调用 native 修饰的方法会进入 本地方法栈 ,然后通过 本地方法接口JNI 调用本地方法。

所以JNI的作用就是扩展Java的使用,融合不同的编程语言为Java使用。jvm会在内存区域中开辟一个标记区域,即本地方法栈,登记所有的native方法,在最终执行时通过JNI加载本地方法库中的方法。(不同虚拟机这里会有所不同)

PC

程序计数器

方法区

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

静态变量(static)、常量(final)、类信息(class)(构造方法、接口)、运行使得常量池 都存放在方法区中,但是,实例变量存在堆中,不是方法区

(最下方就是方法区,存储上面提到的东西)

栈(虚拟机栈)

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

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

栈中的类型:8大基本类型+对象类型+实例方法

实际的栈中存储的是一个个的栈帧,结构大致如下:

在这里插入图片描述

三种JVM

  • sun: HotSpot (openjdk)
  • BEA JRockit
  • IBM J9 VM

结构

Heap,一个JVM仅有一个堆内存,可调节大小

堆中保存的是 实例化的类及方法、常量、变量等

堆内存分为:

  • 新生区(伊甸园区)young
  • 老年区 old
  • 永久区 perm(1.8改为元空间)

GC垃圾回收,主要是在伊甸园区和养老区,,如果内存满了就会出现OOM

具体的结构可以看这里:https://www.processon.com/view/60a25c38f346fb1df41ec011

新生区和老年区

  • 所有实例化 诞生和成长的地方,甚至死亡
  • 主要分为 伊甸园区幸存者区(S0, S1)

当伊甸园区满后,会进行一次轻量级垃圾回收,对于还存在的对象将转到幸存者区。如果新生区老年区满了会进行一次重量级垃圾回收,将存活的转到老年区,全部满了表示没有内存空间,即OOM

整个流程大致如下:

永久区(元空间)

常驻内存,用来存放JDK自身携带的Class对象。Interface元数据,存储的是Java运行时的一些环境或类信息,不存在垃圾回收,仅在关闭虚拟机时释放

一个启动类,如果加载大量的第三方jar包,如Tomcat部署太多应用,大量动态生成反射类等,会导致OOM

  • 1.6前: 永久代,常量池在方法区
  • 1.7: 永久代,但是退化 去永久代 ,常量池在堆中
  • 1.8: 无永久代,常量池在元空间

Runtime.getRuntime().maxMemroy()Runtime.getRuntime().totalMemroy() 可以获取jvm可以使用的最大内存以及当前初始化的内存大小。

Xms1024m -Xmx1024m -XX:+PrintGCDetails 可以设置初始化内存大小(1/64)与最大内存大小(1/4)。

初始内存大小=新生区+老年区,元数据区在另一个地方

出现OOM的尝试解决方法:

  • Debug分析
  • 内存快照工具分析Dump文件:MAT、Jprofiler

MAT Jprofiler的作用

  • 分析Dump内存文件,快速定位内存泄漏
  • 获得堆中的数据
  • 获得大的对象
  • 。。。

Java虚拟机dump: -Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError[path]

GC:垃圾回收

gc作用于方法区和堆

gc分类:轻GC(YGC)、重GC(Full GC)

gc的算法:标记清除法、标记整理、复制算法、分代收集,

判断对象是否存活的方法:引用计数法和可达性分析

引用计数法

顾名思义,记录每一个对象的引用数,对于没有引用的清理即可

可达性分析

复制算法

新生区中,伊甸园区和两个幸存区间中非空的将存活的对象复制到空的幸存区。其中为空的是 to ,另一个是 from

当一个对象经历15次gc仍存活进入老年区,通过 -XX:MaxTenuringThreshold=5 可以设置进入老年区的时间

  • 好处: 没有内存碎片
  • 坏处:浪费了一部分空间,to是空的

最佳使用场景:对象存活度较低时。

标记清除

对存活对象标记,然后清除

  • 优点:不需要额外空间
  • 缺点:两次扫描费时、内存碎片

标记整理

对标记清除后的整理压缩,,减少碎片

分代收集

对于新生代:使用复制算法

对于老年代:使用标记清除(整理)算法

总结

内存效率:复制算法>标记清除>标记整理

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

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

所以使用分代收集算法,尽可能的提高性能

(JMM指的是Java的内存模型,主要与多线程有关系,就是那8种方式)

一些比较好的总结

https://www.processon.com/view/5ec5d7c60791290fe0768668
https://www.processon.com/view/60a25c38f346fb1df41ec011

对于CMS的学习

以上内容的总结

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值