03.JVM虚拟机(理论类-面试;JVM体系组成,类加载器,堆栈存储结构,GC垃圾回收)

JVM组成

体系架构

JVM简介:JVM,全称 Java Virtual Machine,即Java虚拟机器。旨在一处编译,处处运行。

JVM类型:HotSpot(SUN开发),JRockit(BEA开发),J9 VM(IBM开发)

体系结构:

类加载器

概述:加载器将编译成class文件的Java代码,载入到虚拟机中,并在运行时动态地链接类和其他资源。此外还实现了Java安全模型,控制对代码和资源的访问权限。

分类:启动类加载器(Bootstrap):加载 JAVA_HOME的 lib 库类,或 -Xbootclasspath 参数所指定的路径库,用户无法直接使用,需要new创建,其工作是进行java基本环境(JRE环境)搭建;

扩展类加载器(Extention):由 sun.misc.Launcher$AppClassLoader 实现。它负责 <JAVA_HOME>\lib\ext 目录中的,或者被 java.ext.dirs 指定的类。

应用程序类加载器(Application):加载程序员自己编写的java代码数据库,它负责用户路径 ClassPath 所指定的类库,类由 sun.misc.Launcher$AppClassLoader 实现。

自定义加载器:做框架才会用到。

PS:Bootstrap加载Java系统环境,Extention加载第三方用于功能优化、增强的类,自定义即框架依赖。

双亲委派策略:即用户如果要运行一个class(由Application加载),应用程序类加载器会向上询问Extention,确认此class是否已经存在,若Extention中不存在,Extention会再向上询问Bootstrap,当确定Bootstrap和Extention中都不存在时,class才会被Application加载。

PS:双亲委派策略是一个默认的加载策略,可以更改。

本地接口方法

概述:本地接口,核心技术是JNI,Java Native Interface的缩写,使Java语言实现与本地代码(C/C++等)交互的技术。通过JNI,Java程序可以调用本地方法,并且本地代码也可以调用Java程序中的方法。

目的:提高性能;访问系统资源;调用其他语言的代码;

JVM核心

组成概述

组成:程序计数器、堆、JVM栈、本地方法栈、(静态)方法区

线程私有:方法区和堆

线程共享:栈,本地方法栈,程序计数器。需要进行垃圾回收。

堆:Heap,存储Java程序运行时所创建的对象和数组,通过关键字new来动态地在堆上分配内存空间,并可以自动gc回收。

程序计数器:记录当前程序执行到哪一行,每一个线程都有一个程序计数器,所以它是线程所私有的。

JVM栈(简称栈):栈(stack)是java的一个数据结构,用来存储方法调用的信息,包括局部变量、参数以及程序计数器等。每个线程都有自己独立的栈空间,用来管理当前线程所执行的方法调用。

PS:代码中一个方法调用另一个方法,就称之为压栈,不断压栈会导致栈溢出,抛出 StackOverflowError 异常,此时程序可能会崩溃。一个方法每调用一个方法,会产生一个栈帧

本地方法栈:专门执行 native 修饰的方法的方法栈。

(静态)方法区:用来存储静态的内容,包括静态变量和方法、常量、类信息(构造方法/接口定义)、运行时常量池等,内容具有唯一性(内容不重复),

堆 - Heap

概述:是所有线程共享的部分,堆空间用于存储动态创建的对象和数组等数据结构。

分区:根据优先级,分为新生区、养老区(Tenure Generation Space)、永久存储区(Permanent Space),其中,新生区又可以分为伊甸区(Eden Space)、幸存0区(Survivor 0 Space)、幸存1区(Survivor 1 Space)。

数据在堆内的存储流程:

1、使用 new 创建一个对象,动态地分配内存,先进入伊甸区

2、伊甸区达到一定比例,没有被引用的对象会进行垃圾回收,幸存下来的对象,进入到幸存0区,0区快满则进入1区;

3、一个对象经历15次GC回收依旧存在,则进入养老区

4、养老区将满则进行一次FullGC,进行一次数据清理,若清理完还不够用,则跑数堆溢出异常  Heap Out Of Memory

PS:堆溢出发生在养老区,不会发生在新生区;

OOM 内存溢出异常(Out Of Memory,简称OOM)分为两种,一种是栈溢出,一种是堆溢出;

养老区中的对象一部分是经历GC15次还存在的,一部分是数据量大,占用内存多的对象。

幸存区:根据幸存区中是否存储的有内容,分为From区和To区,有内容的是From区;

PS:新生区中,伊甸区 : S0 : S1 = 8 : 1 : 1 ,每次小GC是回收的Eden区和From区(S0/S1),回收完幸存的数据,翻入TO区,To区就立即变为From区(即有数据的From,无数据的To)。

永久区:jdk1.8之后叫做元空间(Oracle收购BEA公司和SUN公司之后,HotSpot 和 JRockit 两者合并成),元空间一般存jdk自带的jar包。如果项目中存储的jar包比较多,元空间也会撑爆。

PS:Jdk版本从1.6 ---> 1.7 ---> 1.8,常量池位置变化:静态方法区 ---> 堆Heap ---> 元空间(以前的永久区)。

内存设置参数:调整堆内存(-Xms -Xmx)、调整新生区( -Xmn )、调整元空间(-XX:PermSize 和 -XX:MaxPermSize)

内存设置实现:1、在 DataX 中,通过配置 core.json 以调整;

2、在 Tomcat 中,从 tomcat 的配置文件,找到可以修改内存大小的地方调整;

PS:-Xms:表示初始化JAVA堆的大小,默认物理内存的 1/64 ,-Xmx:表示java堆可以扩展到的最大值,默认物理内存的 1/4, 通常将-Xms和-Xmx设置成一样。

内存调优:

前置:查看JVM的GC情况(-XX:+PrintGCDetails 输出详细的GC处理日志),若GC次数很多,则

1、先查看GC的数量发生的位置,新生区?,养老区?,元空间?

2、查看是否进行了频繁的GC,频繁的GC会导致JVM虚拟机特别慢,效率低。

3、内存设置是否比较合理,合理的内存值是调优的关键。

PS:为什么会有最小和最大?

先会按照最小的进行使用,在使用过程中,会满,满了会GC,GC完了会扩容,不断地GC,不段的扩容, 直到达到最大值。

优点:不浪费内存资源,按需分配; 缺点:导致GC次数过多,影响性能。

垃圾回收

回收器种类:目前比较流行的最新进的是G1。常见的有:Serial、SerialOld、ParallelScavenger、ParallelOld、ParNew、CMS、G1、ZGC、Shenandoah、Epsilon等十种;

回收算法

复制算法

标记清除算法(Sweep)

标记整理算法

实现

1、每次将幸存的数据拷贝到新的空间中排列整齐

2、排列完成后格式化原来的数据

1、Mark扫描标记存活对象

2、Sweep回收未被标记对象

3、用free-list记录可用区域

1、Mark扫描标记存活对象

2、二次扫描,将幸存的对象向一端Compact移动。

优点

没有标记和清除过程,效率高

不需要额外空间,内存使用率高

无内存碎片,内存使用率特别高

缺点

一半的空间被浪费

会产生碎片 扫描两次,效率低

慢,特别的慢

适用

幸存对象不多的情况(新生代区域)

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

运行速度:复制算法 > 标记清除 > 标记整理

堆外内存

概述:堆内存分为堆内和堆外,默认说的是堆内,由新生代+老年代+元空间管理,由JVM管理,堆外内存由操作系统管理的那部分区域。

优点:1) 堆外的部分不需要垃圾回收;2) 可以直接持久化写磁盘上,提高效率(IO)

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清雨lxy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值