【3】JVM-OutOfMemory异常重现

  JVM中常见的OOM,那么如何通过自己编写代码产生这些OOM异常呢?通过写代码重现异常,是为了避免在工作中写出有OOM BUG的代码。之前虽然看过相关文章,但是没自己写过这些代码,这次在编写的实际过程中,由于和书本使用的JDK版本不一致,也会有点问题。其中印象最深刻的就是从JDK1.7开始常量池就已经不放在方法区了,而是改到了Java堆中,所以《深入理解JAVA虚拟机》中的有些知识也需要更新了。下面的代码基于JDK1.7来的。并且在运行程序的时候需要设置JVM参数,如果不设置,轻则需要等待很长时间才会出现异常,重则系统假死甚至导致系统内存溢出。

    在测试直接内存的时候,引用了rt.jar中的sun.misc.Unsafe类,如果使用了Eclipse作为IDE,需要修改windows-->preferences-->java-->compiler-->Errors/Warinings,选择Deprecated and restricted API,将Forbidden reference(access rules)修改成ignore。

  1 package org.zsl.learn.oom;
  2 
  3 import java.lang.reflect.Field;
  4 import java.lang.reflect.Method;
  5 import java.util.ArrayList;
  6 import java.util.List;
  7 
  8 
  9 import net.sf.cglib.proxy.Enhancer;
 10 import net.sf.cglib.proxy.MethodInterceptor;
 11 import net.sf.cglib.proxy.MethodProxy;
 12 import sun.misc.Unsafe;
 13 
 14 /**
 15  * 测试在代码中如何产生堆内存溢出、栈溢出(超出长度)、栈内存溢出(栈不能扩展的情况下OOM)、方法区内存溢出、常量池内存溢出
 16  * JDK1.7
 17  * @author Administrator
 18  *
 19  */
 20 public class TestOOM {
 21     private static int count = 1;
 22     private static final int _1MB = 1024*1024;
 23     
 24     List<String> list = new ArrayList<String>();
 25     
 26     //一个普通的对象
 27     static class OOMObjectClass{
 28         public OOMObjectClass(){}
 29     }
 30     
 31     /**
 32      * 通过list对象保持对对象列表的引用,不然GC收集对象,然后不断地向列表中添加新的对象,就会发生OOM
 33      * 
 34      * @VM args:-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError
 35      */
 36     public void testHeapOOM(){
 37         List<OOMObjectClass> list = new ArrayList<>();
 38         while(true){
 39             list.add(new OOMObjectClass());
 40         }
 41     }
 42     
 43     /**
 44      * 通过递归调用方法,从而让方法栈产生栈 StackOverflowError
 45      * 
 46      * @VM args:-verbose:gc -Xss128k
 47      */
 48     public void stackLeak(){
 49         count++;
 50         stackLeak();
 51     }
 52     
 53     
 54     /**
 55      * 除了上述的递归调用可以产生溢出外,还有就是过多的线程,当栈内存无法动弹扩展是,会出现OOM
 56      * 
 57      * 由于在Window的JVM中,Jave的线程是映射到了操作系统的内核线程上,故而这段代码的运行时非常危险的
 58      * 笔者运行的时候限制了JVM内存大小,但是栈内存可以动态扩展,所以电脑内存直接到了90%以上,我果断停止了程序的运行
 59      * 由于栈内存只由-Xss参数控制,并没有办法让其不自动扩展,所以这段代码非常危险
 60      * 参数:-verbose:gc -Xms10M -Xmx10M -Xss2M
 61      */
 62     public void stackLeakByThread(){
 63         while(true){
 64             Thread t = new Thread(new Runnable() {
 65                 
 66                 @Override
 67                 public void run() {
 68                     while (true){
 69                         
 70                     }
 71                 }
 72             });
 73             t.start();
 74             count++;
 75         }
 76     }
 77     
 78     /**
 79      * 常量池是存在于方法区内的,故而只要限制了方法区的大小,当不断新增常量的时候就会发生常量池的溢出
 80      * 
 81      * 笔者使用的是JDK1.7 64位,此时的常量池已经不存在与方法区中,而是迁移到了堆中,故而测试的时候需要限制JVM的堆大小,且不能自动扩展
 82      * @VM args: -Xms10M -Xmx10M
 83      */
 84     public void constantPoolOOM(){
 85         int i=0;
 86         while(true){
 87             list.add(String.valueOf(i++).intern()); //String类型的intern方法是将字符串的值放到常量池中
 88         }
 89     }
 90     
 91     /**
 92      * 方法区是存放一些类的信息等,所以我们可以使用类加载无限循环加载class,这样就会出现方法区的OOM异常
 93      * 主要,使用内部类的时候,需要要使用静态内部类,如果使用的是非静态内部类,将不会发生方法区OOM
 94      * 使用了CGLib直接操作字节码运行时,生成了大量的动态类
 95      * 需要者两个jar包:cglib-2.2.2.jar   asm-3.1.jar
 96      * @VM args:-XX:PermSize=10M -XX:MaxPermSize=10M
 97      */
 98     public void methodAreaOOM(){
 99         while(true){
100             Enhancer eh = new Enhancer();
101             eh.setSuperclass(OOMObjectClass.class);
102             eh.setUseCache(false);
103             eh.setCallback(new MethodInterceptor() {
104                 @Override
105                 public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
106                     return arg3.invokeSuper(arg0, arg2);
107                 }
108             });
109             eh.create();
110         }
111     }
112     
113     /**
114      * 要讨论这部分的内存溢出,首先必须要说一下什么是直接内存:
115      *     直接内存并不是JVM运行时数据区的一部分,也不是JVM规范中定义的内存区域,但是这部分内存也被频繁的使用,也会产生OOM。
116      *     JDK1.4中新加入了NIO类,引入了一种Channel与Buffer的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在JAVA堆里面的DirectByteBuffer对象作为
117      *     这些堆外内存的引用进而操作,这样在某些场景中可以显著的提高性能,避免了在native堆和java堆中来回复制数据。这这部分堆外内存就是直接内存了。
118      * 
119      * 直接内存虽然不会受到JAVA堆大小的限制,但是还是会受到本机内存大小的限制,故而服务器管理员在设置JVM内存管理参数的时候,如果忘记了直接内存,那么当程序进行动态扩展的时候,就有可能发生OOM
120      * 直接内存的容量可以通过-XX:MaxDirectMemorySize指定,如果不指定,那么默认与JAVA堆得最大值一样。
121      * 
122      * @VM args:-Xmx20M -XX:MaxDirectMemorySize=10M
123      * @throws SecurityException 
124      * @throws NoSuchFieldException 
125      * @throws IllegalAccessException 
126      * @throws IllegalArgumentException 
127      */
128     public void directMemoryOOM() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
129         Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
130         unsafeField.setAccessible(true);
131         Unsafe unsafe = (Unsafe)unsafeField.get(null);
132         while(true){
133             unsafe.allocateMemory(_1MB);
134         }
135     }
136     
137     
138     
139     
140     public static void main(String[] args) {
141         TestOOM oom = new TestOOM();
142 //        ---------测试堆内存溢出-----------
143 //        oom.testHeapOOM();    
144         
145 //        ---------测试栈溢出----------
146 //        try{
147 //            oom.stackLeak(); 
148 //        }catch(Throwable error){
149 //            System.out.println("Stack length-->"+count);
150 //            throw error;
151 //        }
152         
153 //        ---------测试由于栈动态扩展导致的OOM----------        
154 //        try{
155 //            oom.stackLeakByThread();
156 //        }catch(Throwable error){
157 //            System.out.println("Stack length-->"+count);
158 //            throw error;
159 //        }
160         
161 //        ----------测试方法区溢出----------
162 //        oom.methodAreaOOM();
163         
164 //        ----------测试常量池溢出----------
165 //        oom.constantPoolOOM();
166         
167 //        ----------测试直接内存溢出----------
168         
169         try {
170             oom.directMemoryOOM();
171         } catch (Exception e) {
172             System.out.println(e);
173         }
174         
175         
176         
177     }
178     
179     
180 }

 

转载于:https://www.cnblogs.com/printN/p/6901668.html

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

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

相关文章

CachedIntrospectionResults 初始化

转载于:https://www.cnblogs.com/xiluhua/p/7862985.html

为什么有些内联(行内)元素可以设置宽高?

为什么有些内联&#xff08;行内&#xff09;元素如img、input可以设置宽高&#xff1f; 在说明之前我们先来了解一些定义。 块级元素和内联元素&#xff1a; ①块级元素总是独占一行&#xff0c;表现为另起一行开始&#xff0c;而且其后的元素也必须另起一行显示。 宽度(w…

mongo数据库和mysql数据库的区别_Mongodb与mysql数据库的区别

MySQLMongoDB说明mysqldmongod服务器守护进程mysqlmongo客户端工具mysqldumpmongodump逻辑备份工具mysqlmongorestore逻辑恢复工具db.repairDatabase()修复数据库mysqldumpmongoexport数据导出工具sourcemongoimport数据导入工具grant * privileges on *.* to …Db.addUser()Db…

在Eclipse中高效运行HTTP / REST集成测试

最近&#xff0c;我有机会使用由我亲爱的Holger Staudacher编写的OSGi-JAX-RS-Connector库。 通过连接器&#xff0c;您可以通过将Path注释的类型注册为OSGi服务来轻松发布资源-实际上&#xff0c;它工作得很好。 对于我来说&#xff0c;使用普通的JUnit测试编写驱动的服务类测…

Eclipse安装TestNG插件

Eclipse安装TestNG插件 TestNG是什么? TestNG按照其文档的定义是&#xff1a; TestNG是一个测试框架&#xff0c;其灵感来自JUnit和NUnit的&#xff0c;但引入了一些新的功能&#xff0c;使其功能更强大&#xff0c;使用更方便。 TestNG是一个开源自动化测试框架;TestNG表示下…

basicdatasourcefactory mysql_Java基础-DBCP连接池(BasicDataSource类)详解

Java基础-DBCP连接池(BasicDataSource类)详解作者&#xff1a;尹正杰版权声明&#xff1a;原创作品&#xff0c;谢绝转载&#xff01;否则将追究法律责任。实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程&#xff0c;为了解决此类性能问题&#xff0c;通常…

生物神经网络衍生出的算法

一个生物神经网络的基本结构&#xff1a; 生物神经网络由大量神经元组成&#xff0c;这些神经元之间通过突触相互连接。神经元可以接收来自其他神经元的信号&#xff0c;并根据信号的强度和类型来调整自己的输出信号。这种神经元之间的相互连接和信号传递形成了生物神经网络的基…

echart实例数据 本地加载_JVM 类加载概述

来源&#xff1a;SegmentFault 思否社区作者&#xff1a;又坏又迷人JVM简介JVM是Java Virtual Machine(Java虚拟机)的缩写&#xff0c;JVM是一种用于计算设备的规范&#xff0c;它是一个虚构出来的计算机&#xff0c;是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Ja…

JPA / Hibernate:基于版本的乐观并发控制

本文是Hibernate和JPA中基于版本的乐观并发控制的简介。 这个概念已经很老了&#xff0c;上面已经写了很多东西&#xff0c;但是无论如何我都看到了它被重新发明&#xff0c;误解和滥用。 我在编写它只是为了传播知识&#xff0c;并希望引起人们对并发控制和锁定的兴趣。 用例…

高可用集群搭建

高可用集群搭建  创建hadoop账户 创建hadoop账户&#xff08;#注意&#xff0c;接下来的操作均在hadoop账户下运行&#xff09; # useradd hadoop # passwd hadoopsu - hadoopmkdir soft disk1 disk2mkdir -p disk{1,2}/dfs/{dn,nn}mkdir -p disk{1,2}/nodemgr/local 将本地目…

scrt如何切换成英文版_英文版SecureCRT显示乱码解决

英文版SecureCRT显示乱码解决系统环境&#xff1a;CentOS&#xff15;.&#xff16;以前Linux都是默认安装在英文环境下&#xff0c;用英文版的SecureCRT查看系统内容输出的也都是英文的&#xff0c;不会出现乱码问题。今天同事在服务器安装时默认选择了简体中文&#xff0c;这…

java try catch_Java捕获异常

大家好&#xff0c;欢迎来到乐字节小乐的Java技术分享园地在Java中&#xff0c;凡是可能抛出异常的语句&#xff0c;都可以用try ... catch捕获。把可能发生异常的语句放在try { ... }中&#xff0c;然后使用catch捕获对应的Exception及其子类。多catch语句可以使用多个catch语…

haproxy文件操作

import os #导入os模块def search(): #定义查找函数 with open(haproxy.txt,r) as f: #只读方式打开文件 value input(请输入您…

多语言持久性:带有MongoDB和Derby的EclipseLink

从现在开始&#xff0c;多语种持久性一直是新闻。 从2011年底开始&#xff0c;在著名的Fowler帖子的推动下&#xff0c;我看到了更多更好的主意。 最新的一个是公司内部的学生项目&#xff0c;我们在其中使用Scala作为后端数据&#xff0c;将数据持久存储到MongoDB&#xff0c;…

web前端开发最佳实践--(笔记之JavaScript最佳实践)

如何避免全局变量污染&#xff1f; 避免定义全局变量或全局函数用一个变量进行封装&#xff0c;并返回外部需要访问的接口如何写出高维护的js代码 配置数据和代码逻辑分离 如&#xff1a; 改成&#xff1a; ---用js模板mustachehandlebarsjsMVC的数据模式 model&#xff1a;数据…

yum mysql5.7位置_CentOS yum 安装 Mysql5.7

1 Steps for a Fresh Installation of MySQL# wget https://dev.mysql.com/get/mysql57-community-release-el6-9.noarch.rpm# yum localinstall mysql57-community-release-el6-9.noarch.rpm以上步骤其实是把 MySQL Yum repository 添加到了系统的 repository list 里去了。ll…

HTML/CSS基础知识(四)

WEB标准和W3C的理解与认识 Web标准是一系列标准的集合。 网页主要由三部分组成&#xff1a;结构&#xff08;Structure&#xff09;、表现&#xff08;Presentation&#xff09;和行为&#xff08;Behavior&#xff09;。 对应的标准也分三方面&#xff1a;结构化标准语言主要包…

python做一个系统代码_python初学者,用python3实现基本的学生管理系统代码实例...

这篇文章分享了管理系统&#xff0c;python学生管理系统的使用&#xff0c;这篇文章非常详细地介绍了通过示例代码实现的学生管理系统&#xff0c;该系统对每个人的研究或工作都有一定的参考学习价值。 这个是用python实现的基本的增删改查的学生管理系统吧&#xff0c;其中主要…

Python入门笔记

Python变量和数据类型 数据类型 print语句 注释 Python的注释以 # 开头&#xff0c;后面的文字直到行尾都算注释 # 这一行全部都是注释... print hello # 这也是注释 什么是变量 定义字符串 字符串可以用或者""括起来表示。 如果字符串本身包含怎么办&#xff1f;比如…

1058. 选择题(20)

原题: https://www.patest.cn/contests/pat-b-practise/1058 思路: 本题主要就是怎么读取数据的问题, 一定要注意scanf函数匹配到 空格或者回车会结束当前变量的赋值, 并且会丢弃这个空格或回车. 关于如何判断一项答题是否正确, 可以采用循环一个一个判断, 也可拼成 字符串用st…