一.请你谈谈实际的项目中在Java虚拟机会抛出哪些异常,每个异常都是怎么产生的?

  1.java.lang.StackOverflowError 栈空间满了

public static void stackOverFlow(){
// 递归调用之后,把栈空间塞满了,当程序出现递归调用没有终止的时候,就会出现此类错误
// Exception in thread "main" java.lang.StackOverflowError
stackOverFlow();
}

  运行结果:

  2.java.lang.OutOfMemoryError: Java heap space 堆空间满了

public static void outOfMemoryHeap() {
// 通过不停的生成新的string对象,把堆空间塞满,堆中没有在存放新的对象,此时会出现该错误
// Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
String str = "itheima";
while (true){
str += str + new Random().nextInt(111111)+new Random().nextInt(22222222);
str.intern();
}
}

 运行结果:

   3.java.lang.OutOfMemoryError: GC overhead limit exceeded GC回收时间过长

public static void outOfMemoryGC() {
/*
* GC回收时间过长时候会抛出OutOfMemoryError,过长的定义是指,超过98%的时间用来做GC并且回收了不到
* 2%的堆内存,连续多次GC都回收不到2%的极端情况下才会抛出.假如不抛出GC overflow limit会发生什么
* 呢?那就是GC清理的内存很快就会被再次填满,迫使GC再次执行,导致CPU的使用率一直在100%,但是GC却没有
* 任何成果.
* 配置JVM参数 -Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
*
* java.lang.OutOfMemoryError: GC overhead limit exceeded
* */
int i = 0;
List<String> list = new ArrayList<>();
try {
while (true){
list.add(String.valueOf(++i).intern());
}
}catch (Throwable e){
e.printStackTrace();
System.out.println("i = "+i);
throw e;
}
}

运作结果:

  

  4.java.lang.OutOfMemoryError: Direct buffer memory 外部内存满了

 public static void outOfMemoryDbm() {
/* 写NIO的程序进场使用ByteBuffer来读取或写入数据,这是一种基于通道和缓冲区的I/O方式,它可以使用
Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块的引用
进行操作.这样可以在一些场景中显著提高性能,因为避免了Java堆和Native堆中来回复制内存
ByteBuffer.allocate(capability) 第一种方式是分配JVM堆内存,属于GC的范围,由于需要拷贝,所有
速度相对较慢
ByteBuffer.allocateDirect(capability)第一种方式是分配OS本地内存,不属于GC管辖的范围,所以
由于不需要进行内存拷贝所以速度相对较快 但如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GCDirectByteBuffer对象们就不会被回收
这时候堆内存充足,但是本地内存已经使用光,再次尝试使用本地内存就会抛出OOM错误,JVM崩溃
JVM配置 -Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
*
java.lang.OutOfMemoryError: Direct buffer memory
nio程序经常出现
*/ System.out.println("JVM最大可用内存: "+ (sun.misc.VM.maxDirectMemory() / (double)1024 / 1024 )+"MB");
try {
TimeUnit.MICROSECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 *1024);
}

运行结果:

  5.java.lang.OutOfMemoryError: unable to create new native thread 无法创建新的本地的线程

public static void outOfMemoryUcnt(){
/*
* 高并发请求服务器时候,会出现如下的错误,准确的来说该异常与对应的平台有关
* 导致原因:
* 1.应用创建了太多线程,一个应用程序创建了多个线程,超过了系统的承载
* 2.服务器并不允许应用程序创建过多的线程,Linux默认允许单个进程可以创建的线程数为1024个
* 应用程序创建的线程超过1024,就会抛出java.lang.OutOfMemoryError: unable to create new native thread
* 解决办法:
* 1.想办法降低应用程序创建的线程数量,分析应用程序是否真的需要创建这么多线程,如果不是,修改代码降低线程数
* 2.对于有的应用,确实需要创建很多线程,远超过Linux系统默认的1024个上限,可以通过修改Linux服务器配置
* 扩大Linux的默认限制 root用户没有限制
* ulimit -u 查看当前的用户下可以允许创建的线程数
* vim /etc/security/limits.d/90-nproc.conf 文件
* */
for (int i = 1; ; i++) {
System.out.println("i = "+i);
new Thread(()->{
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}

运行结果:Windows没有测出来

  6.java.lang.OutOfMemoryError: Metaspace  元空间溢出

    static class OOMTest{}; 内部类

    public static void outOfMemoryMetaSpace(){
/*
* MetaSpace是方法区在HotSpot中的实现,它和持久区最大的区别在于:MetaSpace并不在虚拟机内存而使用本地内存
* 在JDK1.8中,class Metadata 被存储在MetaSpace的native memory
* 永久代(元空间)存放了以下信息
* 1. 虚拟机加载的类信息
* 2. 常量池
* 3. 静态变量
* 4. 即时编译后的代码
* 配置JVM: -XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=9m
*
* */
int i = 0;
try {
while (true){
i++; Enhancer e = new Enhancer();
e.setSuperClass(OOMTest);
e.setUseCache(false);
e.setCallBack(new MethodInterceptor(){
@Override
public Object intercept(Object o,Method method,Object[] objects,MethodProxy methodProxy) throws Throwable{
return methodProxy.invokeSuper(o,args);
}
});
e.create();
}
}catch (Throwable e){
System.out.println("第" + i+"次元空间溢出");
e.printStackTrace();
} }

运行结果:Windows没有出现!!!

二.请你能谈一谈Java的有哪些引用?JVM分别对不同的引用时怎样进行回收的?有什么作用?

  1.强引用

  当内存不足时,JVM会进行垃圾回收,对于强引用对象,就算出现OOM错误也不会对该对象进行垃圾回收,强引用是最常见的普通对象的引用,

  只要还有强引用指向一个对象,就说明这个对象还活着,垃圾回收机制就不会回收这个对象,在Java中,最常见的引用就是强引用,把一个对象赋值

  给一个引用变量,这个引用变量也是强引用当一个变量是强引用时,它处于可达的状态,不被垃圾回收机制回收的.即使该对象以后永远也用不到,JVM

  也不会对其进行回收,因此强引用也是引发Java内存泄漏的主要原因之一.

  对于一个普通的对象,如果没有其它得我引用关系,只要超过了引用的作用域,或者显式的把强引用赋值为null,一般就可以被垃圾回收机制回收.

  

 // 强引用
public static void show01(){ Object o1 = new Object(); // new 出来的对象一般默认是强引用
Object o2 = o1; // o2 引用赋值 o2也是强引用
o1 = null; // 置空
System.gc(); // 手动GC垃圾回收
System.out.println(o1);
System.out.println(o2);
}

运行结果:    o2没有被垃圾回收机制清除

  2.软引用

  软引用是相对于强引用弱化了一些的引用,需要使用java.lang.ref.SoftReference类来实现,可以让对象豁免一些垃圾回收,

  对于软引用的对象来说,当系统的内存充足时,不会被垃圾回收机制回收,当系统的内存不足时,会被垃圾回收机制回收.

  软引用通常用在一些对内存敏感的系统中,比如高速缓存就有用到软引用

//软引用
public static void show02(boolean flag){
if(flag){ // 内存充足
Object o1 = new Object();
SoftReference<Object> softReference = new SoftReference<>(o1);
System.out.println(o1);
System.out.println(softReference.get());
o1 = null;
System.gc();
System.out.println(o1);
System.out.println(softReference.get());
}else{ // 内存不充足设置JVM -Xms5m -Xmx5m -XX:+PrintGCDetails Object o1 = new Object();
SoftReference<Object> softReference = new SoftReference<>(o1);
System.out.println(o1);
System.out.println(softReference.get());
o1 = null;
System.gc();
try {
// 造成OOM,故意制造大对象
byte[] bytes = new byte[30 * 1024 * 1024];
}catch (Throwable e){
e.printStackTrace();
}finally {
System.out.println(o1);
System.out.println(softReference.get()); }
}
}

运行结果:

1.内存充足,o1被置空,但o2没有被回收

2.内存不足 o1,o2都被置为空

  3.弱引用

  需要使用java.lang.ref.WeakReference类来实现,它比软引用的生命周期更短

  对于只有软引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否充足,都会回收该对象所占的内存

  用处:假如有一个应用,需要读取大量的本地图片,如果每次都从硬盘中读取,严重影响速度,如果全部加载到内存,又可能引发OOM

     使用软引用/弱引用可以解决此类问题 

     使用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,

     JVM会自动回收这些缓存图片所占用的空间,从而有效避免OOM问题

    Map<String,SoftReference<BitMap>> imageCache = new HashMap<String,SoftReference<BitMap>>();
 public static void show03(){
Object o1 = new Object();
WeakReference<Object> weakReference = new WeakReference<>(o1);
System.out.println(o1);
System.out.println(weakReference.get());
o1 = null;
System.gc();
System.out.println(o1);
System.out.println(weakReference.get());
}

运行结果: 只要一运行垃圾回收,内存就会被释放

  4.虚引用

  虚引用主要是通过java.lang.ref.PhantomReference类来实现的,与其他的引用类型不同,虚引用并不会决定对象的生命周期

  如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都有可能被垃圾回收机制回收,它不能单独使用也不能

  通过它访问对象,虚引用必须和引用队列来联合使用虚引用的主要作用是跟踪对象被垃圾回收的状态,就是这个对象被收集器回收

  的时候收到一个系统的通知或者后续添加做进一步的处理

 public static void show04(){
Object o1 = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference<>(o1,referenceQueue); System.out.println(o1);
System.out.println(referenceQueue.poll());
System.out.println(phantomReference.get()); System.out.println("---------------------"); o1 = null;
System.gc();
System.out.println(o1);
System.out.println(referenceQueue.poll());
System.out.println(phantomReference.get());
}

运行结果:

   1.虚引用的get()方法永远只返回null

   2.在进行垃圾回收之后,在引用队列中可以看到此对象,主要就是在对象销毁前做出一些通知,类似于Spring的后置AOP

Java虚拟机OOM问题和四大引用问题简述的更多相关文章

  1. POI导出Execl文件,使JAVA虚拟机OOM

    由于在项目中使用POI导出execl,导致JAVA虚拟机OOM,采用以下方式解决问题: 原先方式: g_wb = new XSSFWorkbook(sourceFile.getInputStream( ...

  2. 深入Java虚拟机

    第一章:Java体系结构介绍 1.Java为什么重要?       Java是为网络而设计的,而Java这种适合网络环境的能力又是由其体系结构决定的,可以保证安全健壮和平台无关的程序通过网络传播. 2 ...

  3. [转]JAVA虚拟机的生命周期

    JAVA虚拟机体系结构 JAVA虚拟机的生命周期 一个运行时的Java虚拟机实例的天职是:负责运行一个java程序.当启动一个Java程序时,一个虚拟机实例也就诞生了.当该程序关闭退出,这个虚拟机实例 ...

  4. 深入Java虚拟机读书笔记第五章Java虚拟机

    Java虚拟机 Java虚拟机之所以被称之为是虚拟的,就是因为它仅仅是由一个规范来定义的抽象计算机.因此,要运行某个Java程序,首先需要一个符合该规范的具体实现. Java虚拟机的生命周期 一个运行 ...

  5. Java虚拟机体系结构

    转自:http://www.cnblogs.com/java-my-life/archive/2012/08/01/2615221.html JAVA虚拟机的生命周期 一个运行时的Java虚拟机实例的 ...

  6. 深入理解java虚拟机之垃圾收集器

    Java一个重要的优势就是通过垃圾管理器GC (Garbage Collection)自动管理和回收内存,程序员无需通过调用方法来释放内存.也因此很好多的程序员可能会认为Java程序不会出现内存泄漏的 ...

  7. 深入理解java虚拟机---虚拟机工具jconsole(十八)

    Jconsole,Java Monitoring and Management Console. Jconsole是JDK自带的监控工具,在JDK/bin目录下可以找到.它用于连接正在运行的本地或者远 ...

  8. JVM总结-Java 虚拟机是怎么识别目标方法(上)

    重载与重写 在 Java 程序里,如果同一个类中出现多个名字相同,并且参数类型相同的方法,那么它无法通过编译.也就是说,在正常情况下,如果我们想要在同一个类中定义名字相同的方法,那么它们的参数类型必须 ...

  9. JAVA虚拟机体系结构JAVA虚拟机的生命周期

    一个运行时的Java虚拟机实例的天职是:负责运行一个java程序.当启动一个Java程序时,一个虚拟机实例也就诞生了.当该程序关闭退出,这个虚拟机实例也就随之消亡.如果同一台计算机上同时运行三个Jav ...

随机推荐

  1. mybatis PageHelper分页插件 和 LRU算法缓存读取数据

    分页: PageHelper的优点是,分页和Mapper.xml完全解耦.实现方式是以插件的形式,对Mybatis执行的流程进行了强化,添加了总数count和limit查询.属于物理分页. 一.首先注 ...

  2. Native memory allocation (mmap) failed to map xxx bytes for committing reserved memory

    遇到问题 在服务器上运行 nexus 出现Native memory allocation (mmap) failed to map 838860800 bytes for committing re ...

  3. webpack学习(一)项目中安装webpack

    如何在项目中安装webpack,webpack-cli? 前提:电脑安装了 node和npm包管理工具 1 创建项目文件夹或者在已有的项目中打开终端  输入相关命令: npm init 因为已经安装好 ...

  4. CF1163F Indecisive Taxi Fee

    NOIP之前留的坑 CF1163F Indecisive Taxi Fee 经典问题:删边最短路 在Ta的博客查看 任意找一条最短路E,给E上的点和边新加入一个1~len的编号 最短路上的边变大麻烦 ...

  5. P1065 汪老师的烟

    题目描述 汪老师有n根烟,他每吸完一根烟就把烟蒂保存起来,\(k(k>1)\) 个烟蒂可以换一个新的烟,那么 汪老师 最终能吸到多少根烟呢? 输入格式 每组测试数据一行包括两个整数 \(n,k( ...

  6. H3C 路由的来源

  7. 分析JVM动态生成的类

    总结思考:让jvm创建动态类及其实例对象,需要给它提供哪些信息? 三个方面: 1.生成的类中有哪些方法,通过让其实现哪些接口的方式进行告知: 2.产生的类字节码必须有个一个关联的类加载器对象: 3.生 ...

  8. ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(13)之会员登录注册

    源码下载地址:http://www.yealuo.com/Sccnn/Detail?KeyValue=c891ffae-7441-4afb-9a75-c5fe000e3d1c 会员中心,是我们与用户交 ...

  9. ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(6)之配置文件设置

    现在该有的结构和层级都有了,下面我们就开始实际应用,首先把需要用的js,css,图片放到Content文件夹中. 这里不详细讲解,大家可根据自己的实际情况,使用合适自己的前端框架,也可以点击下载本项目 ...

  10. 2019牛客暑期多校训练营(第二场)F.Partition problem

    链接:https://ac.nowcoder.com/acm/contest/882/F来源:牛客网 Given 2N people, you need to assign each of them ...