一、
Java应用程序 |
JVM |
系统API |
- JVM
- JVM本身是一个规范,规定了不同的厂商要实现的基本功能,比如对class文件的结构校验规则。
- (HotSpot JVM):Oracle公司提供
- JVM运行流程:
.class文件怎么被加载并运行:
1.加载class
2.类对象(Class)存放在方法区,以便以后new对象的时候可以从这个类对象模板来创建真实的对象
3.new出来的对象都是在堆里
4.Java虚拟机栈,每个线程都会分配一个栈,存的是方法调用
5.本地方法栈,保存的是本地方法调用层级
6.程序计数器,保存的是当前代码执行的行号
二、问题
1.JVM运行时数据区包括哪些区域?
(1) 内存共有的
方法区:jdk8 元空间、jdk7 永久的、
堆:JVM 参数设置 -Xms10m 最小启动内存是针对堆的,-Xmx10m 最大运行内存也是针对堆 的。(ms 是 memory start 简称,mx 是 memory max 的简称)
一般最大和最小都设置成一样的。当堆内存设置的比较小时,可能会出现OOM错误,如果出现此问题可以将之设置的大一点。
(2)内存私有的
Java 虚拟机栈:每一个方法都是一个栈帧(入站的元素)栈容量只需要由-Xss参数来设置
如果压入元素过多,会报出StackOverFlow错误
本地方法栈
程序计数器
2.类加载的过程:
(1)加载:
在当前classpath下找到所有.class文件,读取到内存中。
(2)验证:
.class文件的规范:
验证是连接阶段的第一步,这一阶段的目的是确保Class文件的字节 流中包含的信息符合《Java虚拟机 规范》的全部约束要求,保证这些信 息被当作代码运行后不会危害虚拟机自身的安全。
验证选项: 文件格式验证 字节码验证 符号引用验证...
(3)准备:准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值 的阶段。
假如此时有这样一行代码:
public static int value = 123;
它是初始化 value 的 int 值为 0,而非 123
(4)解析:解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程。
(5)初始化:初始化阶段,Java 虚拟机真正开始执行类中编写的 Java 程序代码,将主导权移交给应用程序。初始化 阶段就是执行类构造器方法的过程,初始化完成之后,一个对象就会被创建出来。
3.双亲委派模型:一个类再加载的时候可能使用不同的类加载器
BootStrap :启动加载器
ExtClassLoader : 扩展加载器
AppClassLoader:应用程序类加载器
自定义加载器:编程人员指定的特殊目录
问题:
1.说说Java中有哪些类加载器
BootStrap、ExtClassLoader、AppClassLoader、自定义加载器。
当创建一个类时,先从applicationClassLoader开始向上转发,一直到BooStrapClassLoader
BootStrapClassLoader在自己的家在路径中查找有没有这个类,有则加载,没有则向下转发,
转发到ExtClassLoader,在自己路径中加载,有则加载,没有则向下转发至AppClassLoader,然后再查找。
2.垃圾回收:
我们常说的垃圾回收主要是在堆里面,(栈内存在线程销毁时自动回收)
垃圾回收主要回收的是死亡的对象,释放所占的内存
那么如何去标识一个对象是否死亡?
(1)引用计数法:如果一个对象被引用,那么引用次数就+1,当引用次数为0时那么就意味死亡
(会有内存泄露的风险)
(2)可达性分析:JVM实际采用的方法
在Java语言中,可作为GC Roots的对象包含下面几种:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象;
- 方法区中类静态属性引用的对象;
- 方法区中常量引用的对象;
- 本地方法栈中 JNI(Native方法)引用的对象
没有被标记的对象,在下一轮GC中将会被回收。
3.现在通过可达性算法标记出要回收的对象,如何去回收这些对象
垃圾回收算法:
(1)标记-清除算法:
主要问题:
- 效率问题 : 标记和清除这两个过程的效率都不高
- 空间问题 : 标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中 需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集。
(2)复制算法:把内存区域1中存活的对象,复制到内存区域2中;把内存2中把对象按内存地址的顺序排列好,相当于整理内存空间;把内存区域1的空间整体清空;每次回收重复上述操作
复制算法有明显的空间利用率不足的问题,在使用时只有一般内存能够真正发挥作用
(3)标记整理算法:回收完一块内存之后把存活的对象向一端整理。
在移动对象的过程中,势必会将低效率
4.在GC中到底使用哪个垃圾回收算法?
堆中:新生代,老年代
新生代:复制算法(朝生夕死)频繁GC
老年代:标记-整理算法(频繁GC后存活的对象,移动至老年代)
(1)新生代:Eden区(8) from(s1)(1) to(s2)(1)
a.所有的对象创建都在eden区开辟空间
b.当发生一轮GC之后如果对象没有被回收将会复制到From区
c.第二轮GC时会把eden和from区存活对象都复制到TO区
d.FROM和TO互换位置
e.每次经历一次GC之后,年龄加一,当达到系统设定的年龄后(JVM默认15次后),移动到老年代
面试题:描述垃圾回收的过程?
如果创建一个大对象,eden区放不下,那么这个对象直接放入老年区,参与标记整理算法。
新生代GC:Minor GC
老年代GC:Full GC
垃圾回收器
当GC线程执行的时候用户的线程全部都要停止(STW)
1.单线程收集器(内存小,配置低)
2.并行收集器,使用多线程进程进行瞄和回收
3.随着并行收集器的STW时间越来越长,又开始尝试使用新的收集器缩短STW时间CMS 、G1(全域收集器,基本不会STW)
面试题:垃圾回收器