第一次看到这些真真实实的面试题的时候,我~
这都什么玩意??????? 经过一段时间的研究!!接下来,我将以大白话从头到尾给大家讲讲 不对的地方还请大家指正~ JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 百度的解释云里雾里,对于我们Java程序员,说白了就是: 对于JVM的位置: JDK(Java Development Kit):Java开发工具包 JRE(Java Runtime Environment):Java运行环境 JDK = JRE + javac/java/jar 等指令工具 JRE = JVM + Java基本类库 Java虚拟机主要分为五大模块: 作用:加载 根据结果,我们发现: 我们画图分析以下new一个对象的流程: 那么Class Loader具体是怎么执行我们的 我们编写这样一个程序 级别从高到底 启动类(根)加载器:BootstrapClassLoader 然后再加载 由于引导类加载器涉及到虚拟机本地实现细节,我们无法直接获取到启动类加载器的引用;这就是上面那个程序我们第三个结果为 加载文件存在位置 拓展类加载器:PlatformClassLoader 应用程序加载器:AppClassLoader 用户自定义类加载器:CustomClassLoader 举个例子:我们重写以下java.lang包下的String类 作用总结: 这里引用了这篇博文引用链接,了解即可 Java安全模型的核心就是Java 所有的Java程序运行都可以指定沙箱,可以定制安全策略。 在Java中将执行程序分成 如下图所示 如此严格的安全机制也给程序的功能扩展带来障碍,比如当用户希望远程代码访问本地系统的文件时候,就无法实现。 因此在后续的 如下图所示 在 如下图所示 当前最新的安全机制实现,则引入了 确保Java类文件遵循Java语言规范。这样可以帮助Java程序实现内存保护。但并不是所有的类文件都会经过字节码校验,比如核心类(如上述java.lang.String)。 其中类装载器在3个方面对Java沙箱起作用 虚拟机为不同的类加载器载入的类提供不同的命名空间,命名空间由一系列唯一的名称组成,每一个被装载的类将有一个名字,这个命名空间是由Java虚拟机为每一个类装载器维护的,它们互相之间甚至不可见。 类装载器采用的机制是双亲委派模式。 JNI:Java Native Interface 本地接口的作用是融合不同的编程语言为Java所用,它的初衷是融合C/C++程序 目前该方法使用的越来越少了,除非是与硬件有关的应用,比如通过Java程序驱动打印机或者Java系统管理生产设备,在企业级应用中已经比较少见。因为现在的异构领域间通信很发达,比如可以使用 Socket通信,也可以使用 Web service等等,了解即可!
例如这个例子中,生成了对应的Person模板类,name常量“zsr”放在常量池中,三个对象的引用放在栈中,该引用指向放在堆中的三个实例对象。 这就是堆、栈、方法区的交互关系 又称 举个例子: 最开始,main()方法压入栈中,然后执行a(),a()压入栈中;再调用b(),b()压入栈中;以此往复,a与b方法不断被压入栈中,最终导致栈溢出 实例化的对象 对象诞生、成长甚至死亡的区 Eden区占大容量,Survivor两个区占小容量,默认比例是 存储的是Java运行时的一些环境或类信息,这个区域不存在垃圾回收!关闭虚拟机就会释放这个区域内存! 名称演变 注意:元空间在逻辑上存在,在物理上不存在 新生代 + 老年代的内存空间 = JVM分配的总内存 如图所示: 产生原因: GC垃圾回收,主要在年轻代和老年代 首先,对象出生再 Minor GC:伊甸园区满时触发;从年轻代回收内存 Full GC:老年代满时触发;清理整个堆空间,包含年轻代和老年代 Major GC:清理老年代 什么情况永久区会崩? 一个启动类加载了大量的第三方Jar包,Tomcat部署了过多应用,或者大量动态生成的反射类 这些东西不断的被加载,直到内存满,就会出现 查看我们jvm的
我们可以手动调堆内存大小 利用上述方法指定 内存快照工具: 作用: Dump文件是 举个例子 运行该程序,报错
接下来我们设置以下堆内存,并附加生成对应的 再次点击运行,下载了对应的 一直点击上级目录,直到找到
我们双击打开,可以看到每块所占的大小,便于分析问题 点击 idea中安装插件 下载客户端 https://www.ej-technologies.com/download/jprofiler/files 安装客户端 选择自定义安装,注意:路径不能有中文和空格 后续默认,安装成功即可!!! 安装完成后,重启IDEA,可以看到我们的内存快照工具
打开IDEA的设置,找到Tools里面的JProfiler,没有设置位置则设置位置 此时则全部安装完成! Garbage Collection:垃圾回收 在12.4中,我们已经对GC的流程进行了大概的讲解,这里做一些总结: JVM在进行GC时,并不是对 GC分为两种: 每个对象在创建的时候,就给这个对象绑定一个计数器。 每当有一个引用指向该对象时,计数器加一;每当有一个指向它的引用被删除时,计数器减一。 这样,当没有引用指向该对象时,该对象死亡,计数器为0,这时就应该对这个对象进行垃圾回收操作。 复制算法主要发生在 这也就是
好处:没有内存的碎片(内存集中在一块) 坏处: 最佳使用环境:对象存活度较低的时候,也就是 为每个对象存储一个标记位,记录对象的生存状态 缺点:两次扫描严重浪费时间,会产生内存碎片 优点:不需要额外的空间 又叫做 标记阶段,该算法也将所有对象标记为存活和死亡两种状态; 不同的是,在第二个阶段,该算法并没有直接对死亡的对象进行清理,而是将所有存活的对象整理一下,放到另一处空间,然后把剩下的所有对象全部清除。 可以进一步优化,在内存碎片不太多的情况下,就继续 内存(时间复杂度)效率:复制算法 > 标记清除算法 > 标记压缩算法 内存整齐度:复制算法 = 标记压缩法 > 标记清除法 内存利用率:标记压缩法 = 标记清除法 > 复制算法 没有最优的算法,只有最合适的算法 GC 也称为 对于年轻代: 对于老年代:
Java虚拟机
!!
目录
1、什么是JVM?在哪?
程序
,它能识别.class
字节码文件(里面存放的是我们对.java
编译后产生的二进制代码),并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作!跨平台性
,就是因为JVM,我们可以将其想象为一个抽象层,只要这个抽象层JVM正确执行了.class
文件,就能运行在各种操作系统之上了!这就是一次编译,多次运行
2、JVM、JRE、JDK 的关系
3、JVM体系结构
4、三种JVM(了解)
HotSpot
(我们都用的这个)
JRockit
J9 VM
5、类加载器
.Class
字节码文件1、回顾new对象的过程
public class Student { //私有属性 private String name; //构造方法 public Student(String name) { this.name = name; } }
//运行时,JVM将Test的信息放入方法区 public class Test{ //main方法本身放入方法区 public static void main(String[] args){ //s1、s2、s3为不同对象 Student s1 = new Student("zsr"); //引用放在栈里,具体的实例放在堆里 Student s2 = new Student("gcc"); Student s3 = new Student("BareTH"); System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); System.out.println(s3.hashCode()); //class1、class2、class3为同一个对象 Class<? extends Student> class1 = s1.getClass(); Class<? extends Student> class2 = s2.getClass(); Class<? extends Student> class3 = s3.getClass(); System.out.println(class1.hashCode()); System.out.println(class2.hashCode()); System.out.println(class3.hashCode()); } }
.class
文件,加载初始化生成Student模板类
Student模板类
new出三个对象.class
字节码文件呢,这就引出了我们类加载器~2、类加载器的类别
根据返回结果,我们来讲解以下三种加载器:
c++
编写,加载java
核心库 java.*
,构造拓展类加载器
和应用程序加载器
。根加载器
加载拓展类加载器
,并且将拓展类加载器
的父加载器设置为根加载器
,应用程序加载器
,应将应用程序加载器
的父加载器设置为拓展类加载器
null
的原因。
java
编写,加载扩展库,开发者可以直接使用标准扩展类加载器。ExtClassloader
,Java9以后改名为PlatformClassLoader
java
编写,加载程序所在的目录默认
的类加载器
java
编写,用户自定义的类加载器,可加载指定路径的class
文件
6、双亲委派机制
1、什么是双亲委派机制
BootstrapClassLoader
2、作用
发现报错了,这就是双亲委派机制
起的作用,当类加载器委托到根加载器
的时候,String类
已经被根加载器
加载过一遍了,所以不会再加载,从一定程度上防止了危险代码的植入!!
.class
。通过不断委托父加载器直到根加载器,如果父加载器加载过了,就不用再加载一遍。保证数据安全。.class
,如上述的String类
不能被篡改。通过委托方式,不会去篡改核心.class
,即使篡改也不会去加载,即使加载也不会是同一个.class
对象了。不同的加载器加载同一个.class
也不是同一个class
对象。这样保证了class
执行安全。
7、沙箱安全机制
什么是沙箱?
沙箱
(sandbox)
java中的安全模型演进
本地代码
和远程代码
两种
可信任
,可以访问一切本地资源。不可信信
在早期的Java实现中,安全依赖于沙箱 (Sandbox) 机制。Java1.1
版本中,针对安全机制做了改进,增加了安全策略
,允许用户指定代码对本地资源的访问权限。Java1.2
版本中,再次改进了安全机制,增加了代码签名
。
域 (Domain)
的概念。
系统域
和应用域
系统域
部分专门负责与关键资源进行交互应用域
部分则通过系统域的部分代理来对各种需要的资源进行访问。组成沙箱的基本组件
1.
字节码校验器
(bytecode verifier)2.
类装载器
(class loader)
存取控制器
(access controller):存取控制器可以控制核心API对操作系统的存取权限,而这个控制的策略设定,可以由用户指定。安全管理器
(security manager):是核心API和操作系统之间的主要接口。实现权限控制,比存取控制器优先级高。安全软件包
(security package):java.security下的类和扩展包下的类,允许用户为自己的应用增加新的安全特性,包括:
8、Native本地方法接口
native
:凡是带native关键字的,说明java的作用范围达不到了,会去调用底层c语言的库!进入本地方法栈,调用本地方法接口JNI
,拓展Java的使用,融合不同的语言为Java所用
9、PC寄存器
程序计数器
: Program Counter Register
线程私有
的,就是一个指针,指向方法区中的方法字节码(用来存储指向像一条指令的地址,也即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间
,几乎可以忽略不计
10、方法区
方法区
:Method Area
共享区间
;Non-Heap(非堆)
,目的应该是与Java 堆区分开来。1. 方法区中有啥?
常量池
2. 创建对象内存分析
11、栈
栈内存
,主管程序的运行,生命周期和线程同步,线程结束,栈内存就释放了,不存在垃圾回收
1、栈中存放啥?
2、栈运行原理
栈帧(Stack Frame)
,每个方法被调用和完成的过程,都对应一个栈帧从虚拟机栈上入栈和出栈的过程。
3、堆栈溢出StackOverflowError
public class Test { public static void main(String[] args) { new Test().a(); } public void a() { b(); } public void b() { a(); } }
12、堆
Heap
,一个JVM只有一个堆内存(栈是线程级的),堆内存的大小是可以调节的1、堆中有啥?
2、堆内存详解
1、Young 年轻代
Eden Space(伊甸园区)
:所有的对象都是在此new出来的Survivor Space(幸存区)
幸存0区
(From Space
)(动态的,From和To会互相交换)幸存1区
(To Space
)8:1:1
。2、Tenured 老年代
3、Perm 元空间
永久代
永久代
慢慢退化,去永久代
永久代
改名为元空间
3、什么是OOM?
内存溢出
java.lang.OutOfMemoryError
4、GC垃圾回收
伊甸园区
伊甸园区
只能存一定数量的对象,则每当存满时就会触发一次轻GC(Minor GC)
轻GC
清理后,有的对象可能还存在引用,就活下来了,活下来的对象就进入幸存区
;有的对象没用了,就被GC清理掉了;每次轻GC
都会使得伊甸园区
为空幸存区
和伊甸园
都满了,则会进入老年代
,如果老年代
满了,就会触发一次重GC(FullGC)
,年轻代+老年代
的对象都会清理一次,活下的对象就进入老年代
新生代
和老年代
都满了,则OOM
OOM
14、堆内存调优
1、查看并设置JVM堆内存
堆内存
public class Test { public static void main(String[] args) { //返回jvm试图使用的最大内存 long max = Runtime.getRuntime().maxMemory(); //返回jvm的初始化内存 long total = Runtime.getRuntime().totalMemory(); //默认情况下:分配的总内存为电脑内存的1/4,初始化内存为电脑内存的1/64 System.out.println("max=" + max / (double) 1024 / 1024 / 1024 + "G"); System.out.println("total=" + total / (double) 1024 / 1024 / 1024 + "G"); } }
默认情况下:
在VM options
中可以指定jvm试图使用的最大内存
和jvm初始化内存
大小-Xms1024m -Xmx1024m -Xlog:gc*
-Xmx
用来设置jvm试图使用的最大内存
,默认为1/4-Xms
用来设置jvm初始化内存
,默认为1/64-Xlog:gc*
用来打印GC垃圾回收信息
2、怎么排除OOM错误?
1. 尝试扩大堆内存看结果
jvm试图使用的最大内存
和jvm初始化内存
大小2. 利用内存快照工具JProfiler
3. 什么是Dump文件?如何分析?
进程
的内存镜像
,可以把程序的执行状态
通过调试器保存到dump文件中import java.util.ArrayList; public class Test { byte[] array = new byte[1024 * 1024];//1M public static void main(String[] args) { ArrayList<Test> list = new ArrayList<>(); int count = 0; try { while (true) { list.add(new Test()); count++; } } catch (Exception e) { System.out.println("count=" + count); e.printStackTrace(); } } }
OOM
dump文件
的指令-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
-XX:+HeapDumpOnOutOfMemoryError
表示当JVM发生OOM时,自动生成DUMP文件。Dump
文件
我们右键该类,点击Show in Explorer
.hprof
文件,与src
同级目录下
Thread Dump
,里面是所有的线程,点击对应的线程可以看到相应的错误,反馈到具体的行,便于排错
每次打开Dump文件查看完后,建议删除
,可以在idea中看到,打开文件后生成了很多内容,占内存,建议删除
附:安装Jprofiler教程
这里name和Company任意,License Key大家可以寻找对应版本的注册机获得
15、GC垃圾回收
1、回顾
年轻代
、老年代
统一回收;大部分时候,回收都是在年轻代
2、GC算法
1、引用计数算法(很少使用)
2、复制算法
年轻代
( 幸存0区
和 幸存1区
)
轻GC
,每触发一次,活的对象就被转移到幸存区,死的就被GC清理掉了,所以每触发轻GC
时,Eden区就会清空;From Space
和To Space
,这两块区域是动态交换的,谁是空的谁就是To Space,然后From Space
就会把全部对象转移到To Space
去;复制算法
,其中一个区域会将存活的对象转移到令一个区域去,然后将自己区域的内存空间清空,这样该区域为空,又成为了To Space
;轻GC
后,Eden区清空,同时To区也清空了,所有的对象都在From区幸存0区
和幸存1区
总有一块为空的原因
年轻代
3、标记–清除算法
4、标记–整理算法
标记-整理法
是 标记-清除法
的一个改进版。标记-清楚-压缩法
标记清除
,到达一定量的时候再压缩
总结
思考:有没有最优的算法?
分代收集算法
标记清除+标记压缩
混合实现
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算