组织架构

严格来说,StackOverflowError和OutOfMemoryError都属于错误,而不是异常。

java.lang.StackOverflowError

 public class StackOverflowErrorDemo {
public static void method(){
method();
}
public static void main(String[] args) {
method();
}
}

在上例中,方法的深度调用,导致栈溢出。

java.lang.OutOfMemoryError

java.lang.OutOfMemoryError:Java heap space

 public class JavaHeapSpaceDemo {
private static List<String> list = new ArrayList<>();
public static void main(String[] args) {
String str = "";
while(true){
str += str + new Random().nextInt(111111);
list.add(str);
}
}
}

Java堆用于存储对象实例,不断创建对象,保证这些对象到GC Roots有可达路径,可以避免对象被垃圾回收,很快对象数量就会达到最大堆的容量限制,产生内存溢出异常。

java.lang.OutOfMemoryError:GC overhead limit exceeded

jdk1.6新增的错误类型,GC回收时间过长时会抛出OOM。超过98%的时间用来做GC,但是只回收了2%的堆内存,连续多次垃圾回收,只回收了不到2%的极端情况才会抛出。

经过垃圾回收释放的2%可用内存空间会快速的被填满,迫使GC再次执行,出现频繁的执行GC操作, 服务器会因为频繁的执行GC垃圾回收操作而达到100%的使用率,服务器运行变慢,应用系统会出现卡死现象,平常只需几毫秒就可以执行的操作,现在需要更长时间,甚至是好几分钟才可以完成。

如果不抛出GC overhead limit exceeded,GC会频繁的执行,但是被占用的内存,经过多次长时间的GC操作都无法回收,导致可用内存越来越少,俗称内存泄露。

 public class GCOverheadDemo {
public static void main(String[] args) {
int i =0;
List<String> list = new ArrayList<>();
while (true){
list.add(String.valueOf(++i).intern());
}
}
}

String.intern()是一个Native方法,底层调用C++的 StringTable::intern方法实现。

当通过语句str.intern()调用intern()方法后,JVM 就会在当前类的常量池中查找是否存在与str等值的String,若存在则直接返回常量池中相应Strnig的引用;若不存在,则会在常量池中创建一个等值的String,然后返回这个String在常量池中的引用。

在此为了快速产生这种异常,首先配置VM options为【-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m】,再通过intern()循环创建字符串。从GC的打印日志可以看出,虽然一直在JVM执行GC,但是回收没有效果,最终抛出异常。

java.lang.OutOfMemoryError:Direct buffer memory

产生这种异常的原因是,写NIO程序经常使用ByteBuffer来读取或写入,NIO是一种基于通道和缓冲区的IO方式,它可以使用本地函数库直接分配堆外内存,通过存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样可以在一些情况下显著提升性能,它避免了在Java堆和Native堆中来回复制数据。

ByteBuffer有两种分配内存的方式:

  1. allocate:分配JVM堆内存,属于GC范畴,需要拷贝数据,速度慢。
  2. allocateDirect:分配OS本地内存,不属于GC范畴,不需要内存拷贝,速度较快。

如果不断分配本地内存,堆内存很少使用,JVM也就不需要GC,DirectByteBuffer对象就不会被回收,如果本地内存快被用完了,之后再分配本地内存就会抛出OOM。

java.lang.OutOfMemoryError:unable to create new native thread

高并发请求服务器的时候,经常会出现该异常,该异常与平台有关,导致的原因是应用创建了太多线程,一个应用进程创建多个线程,超过系统承载的极限,服务器不允许创建这么多线程,linux默认允许单个进程创建的线程数是1024个。如果超过允许的值,就会抛出异常。

解决的方法是减少创建线程的数量,尽可能少的创建线程。或者修改服务器配置,扩大限制的线程数量。

java.lang.OutOfMemoryError:Metaspace

Java8之后元空间取代了永久代,元空间的本质和永久代类似,都是JVM规范中方法区的实现,其区别在于元空间不虚拟机中,而是在本地内存中,默认情况下,元空间大小仅受内存限制。主要存放:虚拟机加载的类信息、常量池、静态变量、即时编译后的代码。

解决的方法是通过配置-XX:MaxMetaspaceSize=512m参数,增大Metaspace的空间。

还可以直接去掉 Metaspace 的大小限制。 但是,如果不限制Metaspace内存的大小,当物理内存过载的时候,有可能会引起内存交换,严重拖累系统性能。此外,还可能造成native内存分配失败等问题。

【JVM】关于OOM的二三事的更多相关文章

  1. Java并发编程二三事

    Java并发编程二三事 转自我的Github 近日重新翻了一下<Java Concurrency in Practice>故以此文记之. 我觉得Java的并发可以从下面三个点去理解: * ...

  2. linux杂记(十二?) 关于账号和密码的二三事

    关于密码的二三事 关于账号和密码的二三事 久了不更linux的相关知识,实在是懒得想内容点(纯粹是懒).那么今天就来谈谈关于linux密码和账号的重要概念. 假如你的主机遭到入侵,那么对方的第一个侵入 ...

  3. MySQL5.7关于密码二三事

    MySQL5.7关于密码二三事 第一个:update user set password=password('root') where user='root' and host='localhost' ...

  4. Java中的匿名内部类及内部类的二三事

    匿名内部类适合创建那些只需要使用一次的类,它的语法有些奇怪,创建匿名内部类会立即创建一个该类的实例,这个类定义立即消失,且不能重复使用. 定义匿名类的格式如下: new 实现接口() |父类构造器(实 ...

  5. JVM 字节码(二)方法表详解

    JVM 字节码(二)方法表和属性表 上一节中对 ClassFile 的整体进行了五个详细的说明, 本节围绕 ClassFile 最重要的一个内容 - 方法表的 Code 属性展开 ,更多 JVM Me ...

  6. JVM 内部原理(二)— 基本概念之字节码

    JVM 内部原理(二)- 基本概念之字节码 介绍 版本:Java SE 7 每位使用 Java 的程序员都知道 Java 字节码在 Java 运行时(JRE - Java Runtime Enviro ...

  7. Spark On Yarn Cluster生产环境下JVM的OOM和Stack Overflow问题

    1.Spark on Yarn下JVM的OOM问题及解决方式 2.Spark中Driver的Stack Overflow的问题及解决方式 Spark on Yarn cluster mode: 此时有 ...

  8. Emacs 启动优化二三事

    Emacs 启动优化二三事 */--> div.org-src-container { font-size: 85%; font-family: monospace; } p {font-siz ...

  9. WinForm二三事(三)Control.Invoke&Control.BeginInvoke

    http://www.cnblogs.com/yuyijq/archive/2010/01/11/1643802.html 这个系列从2009年写到2010年,差点又成太监文.随着WPF/Silver ...

随机推荐

  1. RabbitMQ|异步

    目录 RabbitMQ|异步 1 概念|异步 1.1 同步与异步 1.2 比喻 2 生产者消费者设计模式 3 RabbitMQ介绍 3.1 主流消息队列比较: 3.2 RabbitMQ安装(mac电脑 ...

  2. Redis 学习笔记(一) 字符串 SDS

    SDS 简单动态字符串. SDS的结构: struct sdshdr{ int len;//记录BUF数组中已使用字节的数量 ,等于SDS所八寸字符串的长度 int free;//记录BUF数组中未使 ...

  3. Ubuntu 18.04使用OpenSSL自签证书(证书支持多IP及多域名,谷歌浏览器无警告)

    前言 在HTTPS数据传输的过程中,需要用SSL/TLS对数据进行加密和解密,以保证网络传输过程中数据的机密性.HTTPS协议可以大致分为两个部分:其一是协商密钥,首先当Client向Web Serv ...

  4. 小程序externalClasses介绍

    小程序externalClasses 1.介绍:我们在封装组件的时候,有时候需要对外暴露出class,可以由调用者来决定组件中一部分的样式,此时就需要使用它了 // components/dong/i ...

  5. 说一说JS的IIFE

    1. 定义IIFE: Immediately Invoked Function Expression,意为立即调用的函数表达式,也就是说,声明函数的同时立即调用这个函数.对比一下,这是不采用IIFE时 ...

  6. 【Linux学习】【第一节】【vi命令】

    在linux下操作文件,通常会用到vi命令,现对其常用命令进行总结. 基本上vi/vim共分为三种模式,分别是命令模式.输入模式和底线命令模式,三者之间的关系如图所示. 一.移动光标的方法 (1)上下 ...

  7. python实现登录密码重置简易操作

    需求: 1.用户输入密码正确登录 2.用户输入密码错误退出并调用函数继续输入 3.用户输入密码符合原先给定的一个值时,允许用户重置密码,并且可以用新密码登录 4.输入三次后禁止输入 虽然贴别的简单,但 ...

  8. Sentinel源码解析一(流程总览)

    引言 Sentinel作为ali开源的一款轻量级流控框架,主要以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度来帮助用户保护服务的稳定性.相比于Hystrix,Sentinel的设计更加简 ...

  9. Rabbit的字符串 字符串最小表示法

    Rabbit的字符串 #include<bits/stdc++.h> using namespace std; ; char s[maxn]; int get_min_pos() { , ...

  10. 实验十四 Swing图形界面组件

    实验十四  Swing图形界面组件 实验时间 20178-11-29 1.实验目的与要求 (1) 掌握GUI布局管理器用法: (2) 掌握各类Java Swing组件用途及常用API: 2.实验内容和 ...