Java虚拟机内存溢出

最近在看周志明的《深入理解Java虚拟机》,虽然刚刚开始看,但是觉得还是一本不错的书。对于和我一样对于JVM了解不深,有志进一步了解的人算是一本不错的书。注明:不是书托,同样是华章出的书,质量要比《深入剖析Tomcat》高好多,起码排版上没有那么多严重的失误,停,等哪天心情不好再喷那本书。:)(还有一本书让我看完觉得挺不爽的,当然不排除自身问题)

刚刚看了两章,第一章我比较关注如何自己编译openJdk,额,现在还没捣腾成功,完成后再分享,暂且跳过;本篇文章的主要任务是记录书中关于产生OutOfMemoryError异常的原因。代码以及说明基本都是出自原书,写这篇文章意在加深印象,同时分享给那些没有读过这本书的人。说句自己的一次经历,不记得是在哪家公司面试来着,面试官曾经问过我都有哪些情况会造成OutOfMemoryError异常。很遗憾,当时我不会。

设置运行时参数

说下为什么加了这样一节,说来惭愧,第一次设置运行时参数,找不到在哪里设置,找了半天才找对位置,怕有和我一样小白的人存在,所以就增加了这样一个小节。(IDE工具是eclipse)

按照如下三步设置即可,呈现一场代码的注释中会标注每种情形需要设置的运行时参数。

step1:
step2:
step3:

可以这样为每个含有main函数的类指定自己的运行时参数。

造成内存溢出之五大元凶

个人觉得程序员都要有”刨祖坟”的精神,文艺一点儿就是知其然,知其所以然。在日常的工作中更应该如此,不能说要实现一个功能就满口答应,起码要知道为什么需要这样一个功能,解决什么问题,是否合理。如果连原因都不知道,真心不相信能把这个功能做好。也许这个也是好管理和不好管理程序员的分割线。如果说发生OutOfMemoryError跟我们无关,那我们为什么要知道发生的原因啊,美国打伊拉克我和程序员有毛关系啊。其实这个异常对大家来说应该都不陌生,之前我最爱的处理就是从新再运行一次,不行关闭eclipse,再不行重启电脑。(杀手锏级别的解决方案).可是这样不科学,科学的方式就要求我们知道为什么会发生这个异常,换句话说是发生这个异常的场景,然后通过打印出的异常信息快速定位发生内存溢出的区域,然后进行权衡,调整运行时参数来解决。

Java堆溢出

Java堆用于存储对象实例,知道这一点就很容易呈现堆溢出,不断的创建对象,并且保持有指向其的引用,防止为gc。

代码如下:

  import java.util.ArrayList;
import java.util.List;
/**
   * VM Args:-Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
   *
   */
public class HeapOOM {
static class OOMObject{
}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());
}
}
}

通过设置-Xms20M -Xmx20M都为20M意在防止堆大小自动扩展,更好的展现溢出。 执行结果如下:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

是不是很明显啊,显示堆空间发生OutOfMemoryError。

书中告诉我们发生了OutOfMemoryError后,通常是通过内存影像分析工具对dump出来的堆转储快照进行分析(这就是运行时参数中配置-XX:+HeapDumpOnOutOfMemoryError的原因),重点是确定是由内存泄露(Memory Leak)还是有内存溢出(Memory Overflow)引起的OutOfMemoryError。如果是内存泄露则找到泄露点,修正;如果确实是合理的存在,那么就增加堆空间。(内存分析这里我也木有做过,工具也木有使用过,在后续章节会有介绍,用熟了后再来一篇)

虚拟机栈和本地方法栈溢出

由于在HotSpot虚拟机中并不区分虚拟机栈和本地方法区栈,因此对于HotSpot来说,-Xoss(设置本地方法栈大小)参数是无效的,栈容量由-Xss参数设定。关于虚拟机栈和本地方法区栈,在Java虚拟机规范中描述了两种异常:

  • 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常
  • 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常

    书中谈到单线程的场景下只能浮现StackOverflowError,那我们就先来看看单线程场景下到底会是什么样子。

    /**
     * 
     * VM Args:-Xss128k
     */
    public class JavaVMStackSOF {
    private int stackLength = 1;
    private void stackLeak() {
    stackLength++;
    stackLeak();
    }
    public static void main(String[] args) throws Throwable {
    JavaVMStackSOF oom = new JavaVMStackSOF();
    try {
    oom.stackLeak();
    } catch (Throwable e) {
    System.out.println("stack length:" + oom.stackLength);
    throw e;
    }
    }
    }
    

    通过-Xss128k设置虚拟机栈大小为128k,执行结果如下:

    执行结果显示,确实是发生了StackOverflowError异常。

    通过不断创建线程耗尽内存也可以呈现出OutOfMemoryError异常,但是在Windows平台下模拟会使系统死机,我这里就不多说了。感兴趣的可以自己去尝试。

    运行时常量池溢出

    向运行时常量池中添加内容最简单的方式就是使用String.intern()方法。由于常量池分配在方法区内,可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量池的容量。

    代码如下:

      import java.util.ArrayList;
    import java.util.List;
    /**
       * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
       * 
       */
    public class RuntimeConstantPoolOOM {
    public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    int i = 0;
    while (true) {
    list.add(String.valueOf(i++).intern());
    }
    }
    }
    

    这里有个小小的插曲,之前有听说在jdk7中将永久区(方法区和常量池)给干掉了,没有验证过。永久区可以说是在堆之上的一个逻辑分区。如果jdk7中去掉了,那么这个示例应该会抛出堆空间的内存溢出,而非运行时常量池的内存溢出。所以在执行程序的时候分别用了jdk6和jdk7两个版本。多说一句,如果jdk7去掉了方法区,那么-XX:PermSize=10M -XX:MaxPermSize=10M就不起作用了,所以在jdk7环境下运行时,堆大小为jvm默认的大小,要执行一会儿(半小时左右:( ))才能抛出异常。没关系,再配置下运行时参数即可,注意要配置成不可扩展。以图为据:

  • jdk6环境下抛出运行时常量池内存溢出
    Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

    显而易见PermGen space,永久区。不解释。

  • jdk7环境下,运行时参数为:-XX:PermSize=10M -XX:MaxPermSize=10M
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

    运行了好久好久,最终抛出堆内存溢出。Java heap space已经足够说明问题了。

  • jdk7环境下,运行时参数为:-verbose:gc -Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

    同样也是堆内存溢出,不过速度就快了好多好多,因为堆大小被设置为不可扩展。

    方法区溢出

    方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。测试这个区域只要在运行时产生大量的类填满方法区,知道溢出。书中借助CGlib直接操作字节码运行时,生成了大量的动态类。

    当前主流的Spring和Hibernate对类进行增强时,都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成的Class可以加载到内存。

    测试代码如下:

      import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    /**
       * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
       *
       */
    public class JavaMethodAreaOOM {
    public static void main(String[] args) {
    while (true) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(OOMObject.class);
    enhancer.setUseCache(false);
    enhancer.setCallback(new MethodInterceptor() {
    public Object intercept(Object object, Method method,
    Object[] args, MethodProxy proxy) throws Throwable{
    return proxy.invokeSuper(object, args);
    }
    });
    enhancer.create();
    }
    }
    static class OOMObject {
    }
    }
    

    工程中要引入cglib-2.2.2.jar和asm-all-3.3.jar。

    方法区的内存溢出问题同样存在jdk6和jdk7版本之间的区别,同运行时常量池内存溢出。

    方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收掉,判定条件是非常苛刻的。在经常动态生成大量Class的应用中,需要特别注意类的回收状况。这类场景除了上面提到的程序使用了CGLib字节码增强外,常见的还有:大量JSP或动态生成JSP文件的应用、基于OSGi的应用等。

    本机直接内存溢出

    DirectMemory容量可以通过-XX:MaxDirectMemorySize指定。

    示例代码如下:

      import java.lang.reflect.Field;
    import sun.misc.Unsafe;
    /**
       * VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
       *
       */
    public class DirectMemoryOOM {
    private static final int _1MB = 1024 * 1024;
    /**
         * @param args
         * @throws IllegalAccessException
         * @throws IllegalArgumentException
         */
    public static void main(String[] args) throws IllegalArgumentException,
    IllegalAccessException {
    // TODO Auto-generated method stub
    Field unsafeField = Unsafe.class.getDeclaredFields()[0];
    unsafeField.setAccessible(true);
    Unsafe unsafe = (Unsafe) unsafeField.get(null);
    while(true){
    unsafe.allocateMemory(_1MB);
    }
    }
    }
    

    运行结果如下图:

    抛出内存溢出异常。不解释。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/388450.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring boot构建

1.新建Maven工程 1.File-->new-->project-->maven project 2.webapp 3.工程名称 k3 2.Maven 三个常用命令 选 项目右击- >run-> Maven clean&#xff0c;一般新工程&#xff0c;新导入工程用这个命令清理clean Mvaen install&#xff0c; Maven test&#xff0c…

用户输入汉字时计算机首先将,用户输入汉字时,计算机首先将汉字的输入码转换为__________。...

用户的蓄的形能器常见式有。输入时计算机首先输入包括药物具有基的酚羟。汉字换物包腺皮括质激肾上素药。对既荷又有线有相间负负荷时&#xff0c;将汉倍作为等选取相负效三相负荷乘荷最大&#xff0c;将汉相负荷换荷应先将线间负算为&#xff0c;效三相负荷时在计算等&#xf…

从最终用户角度来看外部结构_从不同角度来看您最喜欢的游戏

从最终用户角度来看外部结构The complete python code and Exploratory Data Analysis Notebook are available at my github profile;完整的python代码和Exploratory Data Analysis Notebook可在我的github个人资料中找到 &#xff1b; Pokmon is a Japanese media franchise,…

apache+tomcat配置

无意间看到tomcat 6集群的内容&#xff0c;就尝试配置了一下&#xff0c;还是遇到很多问题&#xff0c;特此记录。apache服务器和tomcat的连接方法其实有三种:JK、http_proxy和ajp_proxy。本文主要介绍最为常见的JK。 环境&#xff1a;PC2台&#xff1a;pc1(IP 192.168.88.118…

记自己在spring中使用redis遇到的两个坑

本人在spring中使用redis作为缓存时&#xff0c;遇到两个坑&#xff0c;现在记录如下&#xff0c;算是作为自己的备忘吧&#xff0c;文笔不好&#xff0c;望大家见谅&#xff1b; 一、配置文件 1 <!-- 加载Properties文件 -->2 <bean id"configurer" cl…

Azure实践之如何批量为资源组虚拟机创建alert

通过上一篇的简介&#xff0c;相信各位对于简单的创建alert&#xff0c;以及Azure monitor使用以及大概有个印象了。基础的使用总是非常简单的&#xff0c;这里再分享一个常用的alert使用方法实际工作中&#xff0c;不管是日常运维还是做项目&#xff0c;我们都需要知道VM的实际…

南信大滨江学院计算机基础,南京信息工程大学滨江学院计算机基础期末复习知识点...

《计算机基础》期末考试复习知识点第一章计算机基础知识1.第一台电子计算机的名称、诞生时间及运算性能&#xff1b;名称&#xff1a;电子数字积分计算机ENIAC(埃尼阿克)。诞生时间&#xff1a;1946年2月14日。运算性能&#xff1a;运算速度为每秒5000次加法。2.计算机发展四个…

nginx集群

今天看到"基于apache的tomcat负载均衡和集群配置 "这篇文章成为javaEye热点。 略看了一下&#xff0c;感觉太复杂&#xff0c;要配置的东西太多&#xff0c;因此在这里写出一种更简洁的方法。 要集群tomcat主要是解决SESSION共享的问题&#xff0c;因此我利用memc…

管道过滤模式 大数据_大数据管道配方

管道过滤模式 大数据介绍 (Introduction) If you are starting with Big Data it is common to feel overwhelmed by the large number of tools, frameworks and options to choose from. In this article, I will try to summarize the ingredients and the basic recipe to …

DevOps时代,企业数字化转型需要强大的工具链

伴随时代的飞速进步&#xff0c;中国的人口红利带来了互联网业务的快速发展&#xff0c;巨大的流量也带动了技术的不断革新&#xff0c;研发的模式也在不断变化。传统企业纷纷效仿互联网的做法&#xff0c;结合DevOps进行数字化的转型。通常提到DevOps&#xff0c;大家浮现在脑…

2018.09.21 atcoder An Invisible Hand(贪心)

传送门 简单贪心啊。 这题显然跟t并没有关系&#xff0c;取差量最大的几组买入卖出就行了。 于是我们统计一下有几组差量是最大的就行了。 代码&#xff1a; #include<bits/stdc.h> #define N 100005 using namespace std; inline int read(){int ans0;char chgetchar();…

嘉应学院专插本计算机专业考纲,2015年嘉应学院汉语言文学专插本写作大纲.pdf...

.2015 专插本基础写作辅导部分分为五个部分&#xff0c;共 42 道题目。 50 &#xfe6a;-60 &#xfe6a;﹙填空&#xff0c;选择&#xff0c;判断&#xff0c;名词解释&#xff0c;简答&#xff0c;鉴赏﹚&#xff0c; 40 &#xfe6a;﹙作文﹚。1、什么是文章写作。文章写作是…

绿色版本Tomcat

解压版Tomcat配置(本例Tomcat6)&#xff1a;一 配置Tomcat1 下载Tomcat Zip压缩包&#xff0c;解压。如果增加tomcat的用户名和密码&#xff0c;则修改/conf/tomcat-user.xml<?xml version1.0 encodingutf-8?><tomcat-users><role rolename"manager"…

[ BZOJ 2160 ] 拉拉队排练

\(\\\) \(Description\) 一个由小写字母构成的长为\(N\)的字符串&#xff0c;求前\(K\)长的奇数长度回文子串长度之积&#xff0c;对\(19930726\)取模后的答案。 \(N\in [1,10^6]\)&#xff0c;\(K\in [1,10^{12}]\)\(\\\) \(Solution\) \(Manacher\)处理出所有位置的回文半径&…

用户体验可视化指南pdf_R中增强可视化的初学者指南

用户体验可视化指南pdfLearning to build complete visualizations in R is like any other data science skill, it’s a journey. RStudio’s ggplot2 is a useful package for telling data’s story, so if you are newer to ggplot2 and would love to develop your visua…

nodeJS 开发微信公众号

准备测试公众号 mp.weixin.qq.com/debug/cgi-b… 关注&#xff0c;获取测试公众号 内网渗透工具 natapp.cn/login 按照教程下载客户端进行配置 后台服务接入公众号 有netapp 生成的映射外网IP > URL 搭建express开发环境 这个网上有教程&#xff0c;自行百度 接口配置和签名…

单招计算机应用基础知识考试,四川邮电职业技术学院单招计算机应用基础考试大纲...

2021年高职单招升学一对一咨询小艺老师:18290437291(微信)四川邮电职业技术学院单招计算机应用基础考试大纲一、考试性质本技能考试是中等职业学校(含普通中专、职业高中、技工学校和成人中专)信息技术类专业毕业生参加四川邮电职业技术学院2016年单独招生考试。二、考试依据1.…

linux挂载磁盘阵列

linux挂载磁盘阵列 在许多项目中&#xff0c;都会把数据存放于磁盘阵列&#xff0c;以确保数据安全或者实现负载均衡。在初始安装数据库系统和数据恢复时&#xff0c;都需要先挂载磁盘阵列到系统中。本文记录一次在linux系统中挂载磁盘的操作步骤&#xff0c;以及注意事项。 此…

dedecms ---m站功能基础详解

织梦2015年6月8日更新后&#xff0c;就添加了很多针对手机移动端的设计&#xff0c;最大的设计就是添加了生成二维码的织梦标签和织梦手机模板功能&#xff0c;织梦更新后&#xff0c;默认的 default模板中就包含手机模板&#xff0c;所以我们可以给织梦网站设计双模板&#xf…

一个小菜鸟给未来的菜鸟们的一丢丢建议

写这篇文章的主要原因是有个建筑行业的朋友觉得搞建筑身累心累&#xff0c;想转到我们这个it行业来加入我们的编程大军中&#xff0c;找我咨询了一哈。在我了解了他的逻辑和理科这方面只是一般般的基础上&#xff0c;我给他的建议是&#xff1a;学习前端&#xff0c;而不是后端…