JVM探究
- 请谈谈你对JVM的理解,Java8虚拟机和之前有什么变化更新?
- 什么是内存溢出(OOM),什么是栈溢出?怎么分析?
- JVM的常用调优参数有哪些?
- 内存快照如何抓取,怎么分析Dump文件?
- 谈谈JVM中,你对类加载器的认识?
1、JVM的体系结构
2、类加载器和双亲委派机制
要了解双亲委派机制得先了解个概念:
类加载器:“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块成为“类加载器”。
通俗的讲,虚拟机是根据类的全限定名来加载类的,那么有个问题,如果同时存在两个或多个全限定名完全一致的情况下。该如何选择加载哪个类。这就是双亲委派机制要做的工作。
双亲委派机制得工作过程:
1-类加载器收到类加载的请求;
2-把这个请求委托给父加载器去完成,一直向上委托,直到启动类加载器;
3-启动器加载器检查能不能加载(使用findClass()方法),能就加载(结束);否则,抛出异常,通知子加载器进行加载。
4-重复步骤三;
详细见:双亲委派机制
3、沙箱安全机制
什么是沙箱?
Java安全模型的核心就是Java沙箱(sandbox),什么是沙箱?沙箱是一个限制程序运行的环境。沙箱机制就是将 Java 代码限定在虚拟机(JVM)特定的运行范围中,并且严格限制代码对本地系统资源访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。沙箱主要限制系统资源访问,那系统资源包括什么?——CPU、内存、文件系统、网络。不同级别的沙箱对这些资源访问的限制也可以不一样。
4、Native、pc寄存器、方法区
Native
native:凡是带了native关键字的,说明Java的作用范围达不到了,需要调用本地接口方法(其他语言的库)。
1、带了native关键字的,首先会进入运行时数据区中的本地方法栈中,然后调用相应的本地方法接口JNI(Java Native Interface),从本地方法库中找出相应的方法。
2、JNI的作用:扩展Java的使用,融合不同的编程语言为Java所用!最初是为了融合c、c++。
3、它在内存区域中专门开辟了一块标记区域:Native Method Stack(本地方法栈),登记native方法。在最终执行的时候,通过JNI加载本地方法库中的方法。
PC寄存器
程序计数器 program Counter Register
每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,就是即将执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。
方法区 Method Area
方法区是被所有线程共享的,所有的字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,简单的说,所有定义的方法的信息都保存在该区域,此区域属于共享区间;
静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池都存放在方法区中,但是实例变量存在堆内存中,和方法区无关。
5、栈
先进后出
栈内存:主管程序的运行,生命周期和线程同步。线程结束,栈内存也就释放。所以说,不存在垃圾回收的问题。
栈内存存储:8大基本类型、对象引用、实例的方法引用
6、堆
heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的。
当Java程序创建一个类的实例或者数组时,都在堆中为新的对象分配内存。bai虚拟机中只有一个堆,所有的线程都共享他。Java中所有的对象都存放在堆中,包括class对象和异常对象。
其实,堆内存细分为三个区域:
-
新生区(伊甸园区eden、幸存0区survivor0、幸存1区survivor1)
类诞生、成长、甚至死亡的地方
- 伊甸园区,所有的对象都是在伊甸园区new 出来的
- 幸存区(0,1)
-
养老区 old
经过gc垃圾回收幸存留下来的对象存放在这。
其实,99%的对象都是临时对象!
-
永久区(元空间) permanent
这个区域是存放的常驻内存的。用来存放JDK自身携带的class对象。interface元数据,存储的是Java运行时的一些环境或类信息,这个区域不存在垃圾回收!关闭KVM虚拟就会释放这个区域的内存~
在JDK7以及其前期的JDK版本号中。堆内存通常被分为三块区域Nursery内存(young generation)、长时内存(old generation)、永久内存(Permanent Generation for VM Matedata),显演示样例如以下图:
7、GC垃圾回收
JVM在进行GC时,并不是对这三个区域统一回收。大部分时候,都是在新生区
- 新生区
- 幸存区
- 老年区
GC分为两类:轻GC(Miner GC,回收新生区和幸存区中的垃圾)重GC(Full GC,全局回收垃圾,包括老年区)
GC的算法:标记清除法、标记压缩法、复制算法、引用计数法。
引用计数法:
设置一个计数器,记录对象的调用次数,对此来进行垃圾回收。
复制算法:
每次GC后,将新生区和幸存from区中活下来的对象复制存放到幸存to区,同时清空新生区和幸存from区,
此时from区清空后变为to区,to区被复制过去对象后变为了from区。
谁空谁是to区
经历过15次GC后,仍然留下来的对象会转移到老年区中。
标记清除压缩法:
标记清除
1、先将活着的对象进行标记,
2、然后把没有标记的对象删除掉
标记压缩(标记整理)
1、先将活着的对象进行标记
2、然后将标记的对象向前移动压缩。
总结:
内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)
内存整齐度:复制算法=标记压缩算法>标记清除算法
内存利用率:标记压缩算法=标记清除算法>复制算法