jvm java虚拟机理解
请你谈谈你对JVM的理解?
java8虚拟机和之前的变化更新
什么是OOM,什么是栈溢出StackOverFlowError?怎么分析?
JVM的常用调优参数有哪些?
内存快照如何抓取,怎么分析Dump文件?知道吗
谈谈JVM中,类加载器你的认识?
1、JVM的位置
2、JVM的体系结构
3、类加载器
作用:加载class
- 虚拟机自带加载器
- 启动类(根)加载器 BOOT
- 扩展类加载器 EXC
- 应用程序加载器 APP
4、双亲委派机制:为了安全 APP --> EXC --->BOOT
1、防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
2、保证核心.class不能被篡改。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。
5、沙箱安全机制
Java安全模型的核心就是Java沙箱(sandbox) ,
什么是沙箱?沙箱是一个限制程序运行的环境。沙箱机制就是将Java代码限定在虚拟机(JVM)特定的运行范围中,并且严格限制代码对本地系统资源访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。
沙箱主要限制系统资源访问,那系统资源包括什么? CPU、内存、文件系统、网络。不同级别的沙箱对这些资源访问的限制也可以不一样。
所有的Java程序运行都可以指定沙箱,可以定制安全策略。
1 在Java中将执行程序分成本地代码和远程代码两种,本地代码默认视为可信任的,而远程代码则被看作是不受信的。对于授信的本地代码,可以访问一切本地资源。而对于非授信的远程代码在早期的Java实现中,安全依赖于沙箱Sandbox)机制。如下图所示JDK1.0安全模型
2、但如此严格的安全机制也给程序的功能扩展带来障碍,比如当用户希望远程代码访问本地系统的文件时候,就无法实现。因此在后续的Java1.1版本中,针对安全机制做了改进,增加了安全策略,允许用户指定代码对本地资源的访问权限。如下图所示JDK1.1安全模型
3、在Java1.2版本中,再次改进了安全机制,增加了代码签名。不论本地代码或是远程代码,都会按照用户的安全策略设定,由类加载器加载到虚拟机中权限不同的运行空间,来实现差异化的代码执行权限控制。如下图所示
4、当前最新的安全机制实现(也是现在用的),则引入了域(Domain)的概念。虚拟机会把所有代码加载到不同的系统域和应用域,系统域部分专门负责与关键资源进行交互,而各个应用域部分则通过系统域的部分代理来对各种需要的资源进行访问。虚拟机中不同的受保护域(Protected Domain),对应不一样的权限(Permission)。存在于不同域中的类文件就具有了当前域的全部权限,如下图所示最新的安全模型(jdk 1.6)
组成沙箱的基本组件
字节码校验器(bytecode verifier):确保Java类文件遵循Java语言规范。这样可以帮助Java程序实现内存保护。但并不是所有的类文件都会经过字节码校验,比如核心类。
类裝载器(class loader) :其中类装载器在3个方面对Java沙箱起作用
它防止恶意代码去干涉善意的代码;//双亲委派机制
它守护了被信任的类库边界;
它将代码归入保护域,确定了代码可以进行哪些操作。
虚拟机为不同的类加载器载入的类提供不同的命名空间,命名空间由一系列唯一的名称组成, 每一个被装载的类将有一个名字,这个命名空间是由Java虚拟机为每一个类装载器维护的,它们互相之间甚至不可见。
类装载器采用的机制是双亲委派模式。
1.从最内层JVM自带类加载器开始加载,外层恶意同名类得不到加载从而无法使用;
2.由于严格通过包来区分了访问域,外层恶意的类通过内置代码也无法获得权限访问到内层类,破坏代码就自然无法生效。
存取控制器(access controller) :存取控制器可以控制核心API对操作系统的存取权限,而这个控制的策略设定,可以由用户指定。
安全管理器(security manager) : 是核心API和操作系统之间的主要接口。实现权限控制,比存取控制器优先级高。
安全软件包(security package) : java.security下的类和扩展包下的类,允许用户为自己的应用增加新的安全特性,包括:
安全提供者
消息摘要
数字签名 keytools https
加密
鉴别
6、Native
1、native:用native关键字。说明java的作用范围打不到了,回去调 用底层C语言库。
2、JNI的作用:扩展java的使用,融合不同的编程语言为java所用: 最初C,C++。java诞生时c、c++横行,要立足就要调用c、c++
3、JNI在内存区域中专门开辟了一块标记区域:本地方法栈 Native Method Stack,登记了native方法。
4、执行的时候native方法会从本地方法栈,调用本地方法接口 (JNI java native interface)通过JNI 加载本地方法库中的方法。
5、在企业级应用中较为少见,通过java驱动打印机、robot等情况下 使用,掌握即可。
7、PC寄存器
程序计数器:Program Counter Register
每个线程都有一个程序计数器,是线程私有的,储存即将执行的 指令代码的地址,占用内存空间非常小,(用来计数使线程有序等, 比如线程1 线程2 线程...)
8、方法区(共享区间)
1、静态变量、常量、类信息(构造方法、接口定义)、运行时常量池 都 存在方法区中
2、实例化时 实例和实例变量赋值存在堆内存中
3、栈中存放实例的引用,方法执行时入栈,方法执行完弹栈
4、方法区和堆 有垃圾回收,栈中没有
9、栈
队列:管形、先进先出(FIFO first input first output)
栈:存放8大基本类型,对象的引用,实例的方法
桶形:先进后出
main()方法先执行,最后执行结束
栈内存 主管程序运行,生命周期和线程同步
线程结束,栈内存也就是释放了。栈不存在垃圾回收
栈帧:栈顶、栈底(程序正在执行的方法一定在栈的顶部)
每个栈帧中有:方法的索引、入参出参、本地变量、Class File、父帧、子帧
10、对象的初始化
父类的静态代码块
->子类的静态代码块
->初始化父类的属性值/父类的普通代码块(自上而下的顺序排列)
->父类的构造方法
->初始化子类的属性值/子类的普通代码块(自上而下的顺序排列)
->子类的构造方法。
注:构造函数最后执行。
11、三种JVM
Sun公司 HotSpot(一般用)
BEA公司JRockit
IBM公司J9 VM
12、堆 Heap
一个JVM只有一个堆内存,堆内存的大小是可以调节的。
类加载器读取了类文件后,一般把什么放入堆中?类、方法、常量、变量、所有引用类型的真实对象
13、新生区(Eden Space) 轻量级GC(轻GC)
新生区:伊甸园区、幸存区012345...
N次(定义上限)垃圾回收之后,进入养老区
14、老年区:重量级GC(Full GC)
GC,主要在伊甸园区和养老区。
内存满了,报OutOfMemory堆内存错误。
99%的对象都是临时对象,进不到养老区。
15永久区(JDK8之后叫 元空间)
不存在GC,关闭VM虚拟机就会释放这个区域的内存。
这个区域是常驻内存的。用来存放JDK自身携带的Class对象。Interface元数据,存的是java运行时的一些环境或类信息。
一个启动类加载了大量的第三方jar包、Tomcat部署了太多应用大量动态生成反射类。不断加载直到内存满了,就会报OOM。
Jdk6前:永久代,常量池在方法区中
Jdk7:永久代,常量池在堆中
Jdk8后:无永久代,常量池在元空间
1.8时的堆:方法区中包含一小块常量池
元空间:逻辑上存在,物理上不存在
16堆内存调优
1、OOM的处理 :设置内存 -Xms4096m -Xmx256m -XX:+PrintGCDetails
1、尝试扩大堆内存,看结果
2、分析内存,看一下哪个地方除了问题(用专业工具)
2、在项目中突然出现OOM故障,如何排除:
1、Dubug一行行分析:不现实
2、通过插件直接看到第几行出错:内存快照分析工具:MAT、Jprofiler
3、MAT,Jprofiler的作用:
1、分析Dump内存文件,快读定位内存泄漏
2、获得堆中的数据
3、获得大的对象
等等
//设置内存 -Xms4096m -Xmx256m -XX:+PrintGCDetails (打印GC信息到控制窗口)
//堆Dump -Xms4096m -Xmx256m -XX:+HeapDumpOnOutOfMemoryError (on后面是条件)
17、GC常用算法:标记清除法、标记压缩、复制算法、引用计数器法
1、引用计数法:一般不用引用计数法,给每个对象分派程序计数器,计数为0的回收
2、复制算法:每次GC,都会将Eden区中活着的对象移到幸存区中幸存区,幸存区放不下就放到养老区了。Eden区被GC后就是空的。幸存区谁空谁是to,非空from
复制算法的缺点:浪费一半空间(to得是空的),从from幸存区复制到to幸存区,如果对象 都存活,太浪费资源。因此当对象存活率低才会用复制算法
3、标记清除:回收时对活着得对象扫描进行标记,对没标记得对象扫描进行清除
缺点:两次扫描,严重浪费时间,会产生内存碎片
优点:对比复制算法 不需要额外的内存空间(空的To幸存区)
4、标记压缩:在标记清除得基础上,再次扫描,向一端移动存活得对象,防止内存碎片产生。又多了一个移动的成本
5、最好进行多次标记清除,然后进行一次标记压缩,降低成本
17、总结
内存效率(时间复杂度):复制算法 > 标记清除算法 > 标记压缩算法
内存整齐度:复制算法 = 标记压缩 > 标记清除算法
内存利用率:标记压缩算法 = 标记清除算法 > 复制算法
GC是分代收集算法:
年轻代:存活率低 用 复制算法
老年代:区域大,存活率高 用 标记清除+压缩混合
JVM学会之后想深入研究可看《深入学习JVM》
也可研究新的模型:JMM
Java Memory Model
什么是JMM ? 百度百科
干嘛的? 官方、博客、对应视频
如何学习?看 + 面试题