这是一篇看了能说的出来的jvm面试;我的能力有限,文中描述不免有错误,请指正;html
jvm会将运行程序所管理的空间分为若干部分,每一个部分都起到相当重要的部分;jdk1.8java运行时数据区以下:java
程序计数器
:当前线程执行字节码的行号指示器;字节码解析器经过改变计数器的值,来选取下一条须要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能;面试
Java 虚拟机栈
: java方法执行的内存模型,每一个方法被执行的时候都会建立帧栈用于存储局部变量表、操做数栈、动态连接、方法出口等信息;算法
本地方法栈
: 执行java的native方法服务,每一个方法被执行的时候都会建立帧栈用于存储局部变量表、操做数栈、动态连接、方法出口等信息;数组
Java 堆
: 储存对象的实例和数组;安全
方法区
: 非堆,储存类的结构信息;例如运行时常量池的字段和方法数据,构造函数和普通方法的字节码内容等;并发
科普运行时经常使用池:运行时经常使用池是class文件中每个类或者接口的常量池表的运行表现形式,包括若干种常量,如字段和方法的引用;在类加载至虚拟机的时候就会建立运行时常量池;科普帧栈:帧栈用于储存数据和部分过程结果的数据,同时也会处理动态连接,方法返回值和分派;帧栈随着方法的建立而建立,随着方法的销毁而销毁;帧栈中维护着本地变量表,操做数栈,和指向当前方法所属类的运行常量池的引用;oracle
注意:jdk1.8已经使用元空间替代了jdk1.7方法区中的永久代,元空间存在于native内存中,其大小根据本地内存而定,没有限制;详细看官网地址jvm
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/considerations.html#sthref66socket
类的加载过程分为 加载,连接,初始化,使用,和卸载5个阶段,其中链接阶段又分为验证 准备和解析阶段;
内存溢出:申请了8个字节的空间,可是你在这个空间写入9或以上字节的数据,出现内存溢出;
在java内存模型中只有程序计数器不会发生OOM(out of memory),其他地区都会发生OOM;
当一个类收到了类加载请求时,本身不会先去加载这个类,而是将其委派给父类去加载,若是父类不能加载,反馈给子类,由子类去完成类的加载;
这边有可能会问,你都知道哪些类加载器:
如何打破双亲委派模型?
双亲委派模型都依靠loadClass()
,重写loaderClass()
便可;
新生代分为 3 个分区:Eden(伊甸园)、Survivor一、Survivor2;其中Survivor一、 Survivor2 合起来成为Survivor(幸存区); 若是没有Survivor,Eden区每进行一次Minor GC
,存活的对象都会被送到老年代。老年代将很快被填满,老年代每发生一次Full GC
的速度比 Minor GC
慢10倍;
Survivor 的做用就是减小老年代Full GC
的次数,至关于缓冲带;Eden和Survivor的比例分配8:1;
官网:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/generations.html#sthref16
会出现的小问题就是:Minor GC和Full GC触发条件,答默认状况下发生15次Minor GC以后就会触发一次Full GC
GC 是垃圾收集(GabageCollection);Java 提供的 GC 功能能够自动监测对象是否超过做用域从而达到自动回收内存的目的,而不须要人为手动释放内存;主要调用的是 System.gc() 和 Runtime.getRuntime().gc();
CMS(Concurrent Mark Sweep)收集器基于标记—清除算法
实现的收集器,是一种以获取最短回收停顿时间为目标的收集器。主要优势是并发收集,低停顿,在cpu多核的状况下性能较好。在启动 JVM 的参数加上
“-XX:+UseConcMarkSweepGC”来指定使用 CMS 垃圾回收器;其使用在老年代 能够配合新生代的Serial和ParNew收集器一块儿使用;因为 CMS 使用 标记—清除算法
GC时会产生大量碎片,有可能提早触发Full GC;若是在老年代充满以前没法回收不可达对象,或者没有足够的空间知足分配就会致使Concurrent Mode Failure(并发模式故障);
官网:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html
G1(Garbage-First)从总体来看是基于标记—整理
算法实现的收集器,可以实现并发并行,对cpu利用率较高,减小停顿时间。目标是取代jdk1.5发布的CMS收集器。G1收集器收集范围是老年代和新生代
,不须要结合其余收集器使用,G1收集器可预测垃圾回收的停顿时间,对空间进行整合;因为G1是基于复制算法实现,当没有足够的空间(region)分配存活的对象就会致使Allocation (Evacuation) Failure(分配失败);
官网:
官网:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html#sthref27
Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其余全部线程都被挂起。Stop-The-World对系统性能存在影响,所以垃圾回收的一个原则是尽可能减小“Stop-The-World”的时间;
标记-清除法
:标记出没有用的对象,以后一个一个回收掉
复制算法
: 按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另外一块上,而后再把已使用的内存空间一次清理掉
标记-整理法
:标记出没有用的对象,让全部存活的对象都向一端移动,而后直接清除掉端边界之外的对象
分代回收
:根据对象存活周期的不一样将内存划分为几块,通常是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法
内存泄漏:new申请了一块内存,后来很长时间都再也不使用了(按理应该释放),可是由于一直被某个或某些实例所持有致使 GC 不能回收;
经典案例
void test(){
Vector vector = new Vector();
for (int i = 1; i<100; i++)
{
Object object = new Object();
vector.add(object);
object = null;
}
//...对vector的操做
//...与vector无关的其余操做
}
手动解决赋值null便可
void test(){
Vector vector = new Vector();
for (int i = 1; i<100; i++)
{
Object object = new Object();
vector.add(object);
object = null;
}
//...对vector的操做
vector = null;
//...与vector无关的其余操做
}
还有各类流和socket的close方法未被调用也会发生内存泄漏问题;
不会,在下一个垃圾回收周期中回收对象。
若是你对文中的知识点不太理解 推荐阅读周志明先生《深刻理解Java虚拟机:JVM高级特性与最佳实践(第3版)》和做者给出的官网连接!!!!
求关注吖