文档章节

手写jvm中的各种OOM

温安适
 温安适
发布于 2017/06/28 22:22
字数 1706
阅读 210
收藏 5
点赞 0
评论 0

 前言

    大家好,这篇blog不写什么实际技术,就把我从书上学来的,制造JVM各种OOM的方法告诉大家。下回在遇到有人问你Java会内存溢出吗?你可以快速回答他,会!我还会写各种bug,造成JVM出现OOM异常。

知己知彼,JVM的各个区域的特定

要想写出各种OOM,必须知道JVM各个区域的特点,以便针对性的写bug,造成OOM。下面是我看书后总结的JVM各个区域的特点:

区域名称 作用 是否线程私有 是否会
内存溢出
溢出原因
程序计数器 当前线程所执行的字节码的行号的指示器。
每个线程都有独立的程序计数器
 
Java虚拟机栈 与线程同生命周期存储局部变量表,操作数栈
动态链接,方法出口,对象引用等。
局部变量表存储基本数据类型
boolean,int,float,long,
double,byte,short.
long,double占2其余占1局部空间
2种异常
1.StackOverflowError,
线程请求的栈深度大于虚拟机所允许的深度。
2.OutOfMemoryError
栈扩展时申请到不足够的内存。
本地方法栈 Java虚拟机栈类似
为Native服务
2种异常
1.StackOverflowError,线程请求的栈深度大于
虚拟机所允许的深度。
2.OutOfMemoryError
栈扩展时申请到不足够的内存。
java堆 存放对象实例以及数组。
GC堆。
逻辑连续,物理不连续
通过-Xmx和-Xms来控制。
堆中内存不足,无法完成实例分配,并且堆无法再扩展时。
将抛出OutOfMemoryError
方法区 non-heap,“永久代”
受到-XX:MaxPermSize
当方法区无法满足内存分配需求时OutOfMemoryError
运行时常量池 字面量,符号引用。Java语言
不一定要求只有编译才会产生常量
String的interm()是方法区的一部分
JDK1.7将它从方法区移除,使用直接内存
受方法区限制(1.7以后不会).当常量池无法再申请到内存
时会内存溢出
直接内存 即本机直接内存,不受JVM控制。 JVM各内存区域总和大于物理内存时,
当再动态扩展时会OutOfMemoryError

 逐个击破,实战各种OOM

下面的例子均来自《深入理解Java虚拟机第二版本》,不过我结合了IDEA进行了实战操作,对设置参数进行了注释,也算是精炼了实战OOM的方法。

java堆(GC堆)的OOM

java堆出现OOM的情况如下:

    堆中没有内存完成实例分配时,并且堆无法再扩展时。将抛出OutOfMemoryError。

为了让java堆(GC堆)更容易出现OOM,我们需要把JVM的堆内存分配的小一点,需要用到的参数如下:

  -Xms20m (JVM初始分配的堆内存)

  -Xmx20m(最大可使用内存)

  -XX:+HeapDumpOnOutOfMemoryError(r,JVM会在遇到OutOfMemoryError时拍摄一个“堆转储快照”)(可以不设置,对造成OOM没有帮助)

在IDEA中设置这些参数的方法如下:

1.先运行一遍写好的程序

2.之后在Run选项中选择Edit Configurations

之后如下图进行设置。

造成GC堆OOM的代码如下:

    其核心就是不断的生产对象,并保证已生产对象存活。利用List,维护所有OOMObject对象存活(利用list保存所有OOMObject都有引用),并利用集合自动扩展申请新的内存,直至Java堆剩余空间,不满足新的OOMObject对象所需的空间为止。

/**
 * Created by Administrator on 2017/6/22.
 * -Xms20m (JVM初始分配的堆内存)-Xmx20m(最大可使用内存)
 * -XX:+HeapDumpOnOutOfMemoryError(r,JVM会在遇到OutOfMemoryError时拍摄一个“堆转储快照”)
 */
public class HeapOOM {

    static class OOMObject{

    }

    public static void main(String[]args){
       //利用List,维护所有OOMObject对象存活,并利用集合自动扩展申请新的内存。
        List<OOMObject>list=new ArrayList<OOMObject>();
        while(true){
            list.add(new OOMObject());
        }
    }
}

Java虚拟机栈OOM

虚拟机栈理论上有2种异常:
  1.StackOverflowError,线程请求的栈深度大于虚拟机所允许的深度。
  2.OutOfMemoryError栈扩展时申请到不足够的内存。

实验中,StackOverflowError非常容易出现,OutOfMemoryError从未出现过,网友可以尝试下。

下面仅介绍如何生成StackOverflowError。

为了让JVM,更容易出现StackOverflowError,我们需要设置如下参数:

-Xss128k(设置每个线程的堆栈大小 为128K)。设置方法如上,不在赘述。

造成虚拟机栈StackOverflowError的方法

这里利用死递归(没有出口的递归),不断的往虚拟机栈中加入递归上下文信息。

/**
 * Created by Administrator on 2017/6/22.
 * -Xss128k(设置每个线程的堆栈大小 为128K)
 */
public class JavaVMStackSOF {

    private int stackLength=1;

    public void stackLeak(){
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) {
        JavaVMStackSOF sof=new JavaVMStackSOF();
        sof.stackLeak();
    }
}

方法区内存溢出

方法区存放类的相关信息,我们可以不断生成新的类信息到方法区,直到撑爆方法区。

如何动态产生类信息呢?JavaAPI中有反射, 但是很多框架中都是用CGLib,例如Spring。这里也使用CGLib.

其代码如下:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

/**
 * Created by Administrator on 2017/6/23.
 */
public class JavaMethodAreaOOM {

    static  class OOMObject{

    }

    public static void main(String[] args) {
        while (true){
            //创建增强器
            Enhancer enhancer=new Enhancer();
            //设置要增强的父类
            enhancer.setSuperclass(OOMObject.class);
            //不使用缓存很重要,保证更容易触发OOM
            enhancer.setUseCache(false);
            //不增强任何方法
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    return methodProxy.invoke(o,objects);
                }
            });
           //创建增强后的类
            enhancer.create();
        }
    }
}

本地内存直接溢出

Java中何时会使用动态内存呢?NIO中的Channel,使用NIO比较繁琐,我们使用直接分配本地内存的方式,造成内存溢出。Unsafe类可以直接分配本地内存。

为了让容易造成本地内存直接溢出,我们设置参数:

--XX:MaxDirectMemorySize=10M(JVM使用本地内存上限为10M)

设置方式如上。

造成本地内存直接溢出的代码为:

import sun.misc.Unsafe;
import java.lang.reflect.Field;

/**
-Xmx20m --XX:MaxDirectMemorySize=10M
 * Created by Administrator on 2017/6/23.
 */

public class DirectMemoryOOM {
    private  static final  int _1MB=1024*1024;

    public static void main(String[] args) throws IllegalAccessException {
        //theUnsafe;d对象
        Field unsafeField= Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        //但是如果字段是静态字段的话,传入任何对象都是可以的,包括null,这里获得theUnsafe对象
        Unsafe unsafe= (Unsafe) unsafeField.get(null);
        while (true){
            //指派内存1MB
            unsafe.allocateMemory(_1MB);
        }
    }
}

总结

到此我们对JVM大部分区域,进行了针对性的OOM实战。有一些没有实战的,网友可以自行尝试。

查阅了这篇文章,我希望你可以很自豪的说,我能够写bug,造成JVM内存溢出了!

 

 

© 著作权归作者所有

共有 人打赏支持
温安适
粉丝 100
博文 22
码字总数 37443
作品 0
朝阳
后端工程师
JVM内存管理:深入Java内存区域与OOM

Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来。 概述: 对于从事C、C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高...

underA
2013/10/24
0
0
深入理解Java虚拟机:JVM高级特性与最佳实践(一):java 内存区域与内存异常

如需转载,请标明转自何处 运行时数据区域: java 虚拟机在执行java程序的过程中会把他管理的内存化为若干个不同的数据区域。这些区域都有各自的用途,销毁与创建的时间,有的区域随着进程的...

熊大熊二
2015/11/03
0
0
java虚拟机运行时的内存分类以及出现异常分析(jvm之一)

java虚拟机所管理的内存包括以下几个运行时数据区域: 方法区(Method Area):线程共享的,存放已被虚拟机记载的类信息、常量、静态变量等数据。“永久代(Permanent Generation)” 虚拟机...

zhengDavid
2012/06/13
0
0
Android Bitmap变迁与原理解析(4.x-8.x)

App开发不可避免的要和图片打交道,由于其占用内存非常大,管理不当很容易导致内存不足,最后OOM,图片的背后其实是Bitmap,它是Android中最能吃内存的对象之一,也是很多OOM的元凶,不过,在...

看书的小蜗牛
05/22
0
0
Java jvm内存调优(来自小强公开课)

Java jvm内存调优 Jdk:java开发工具包 Jre:java运行环境,运行你编写的java程序 Jvm:java虚拟机,.class文件在虚拟机上运行 如何选择合适的java虚拟机 》》》选择稳定的jdk(慎用新出的,...

32氪
06/26
0
0
Java中常见OOM的场景及解决方法

OOM for Heap (java.lang.OutOfMemoryError: Java heap space) 分析 此OOM是由于JVM中heap的最大值不满足需要,将设置heap的最大值调高即可,参数样例为:-Xmx2G JVM堆的设置是指Java程序运行...

ikilun
06/26
0
0
Android Out Of Memory(OOM) 的详细研究

基于Android开发多媒体和游戏应用时,可能会挺经常出现Out Of Memory 异常 ,顾名思义这个异常是说你的内存不够用或者耗尽了。 在Android中,一个Process 只能使用16M内存,如果超过了这个限...

caikezhan
2013/10/15
0
0
从几个sample来学习Java堆,方法区,Java栈和本地方法栈

最近在看《深入理解Java虚拟机》,书中给了几个例子,比较好的说明了几种OOM(OutOfMemory)产生的过程,大部分的程序员在写程序时不会太关注Java运行时数据区域的结构: 感觉有必要通过几个...

LCZ777
2014/08/31
0
0
jvm优化必知系列——监控工具

这是jvm优化系列第二篇: jvm优化——垃圾回收 通过上一篇的jvm垃圾回收知识,我们了解了jvm对内存分配以及垃圾回收是怎么来处理的。理论是指导实践的工具,有了理论指导,定位问题的时候,知...

wier
2017/10/18
0
14
25行代码实现一个简单的编译器

起因 《25行JavaScript语句实现一个简单的编译器》实现的是一个简单到不能再简单的玩具的玩具,他的魔法是函数式编程简化了js代码。java 8提供了函数式编程的支持,昨晚脑子抽风突然兴趣jav...

obaniu
2017/11/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

python以太坊类库web3.py概览

python通过web3.py库与以太坊交互共同入口是web3对象。web3对象提供API接口,python开发应用与以太坊进行交互如钱包创建、支付、转账等连接JSON-RPC服务器进行。 Providers提供者 Providers使...

智能合约
1分钟前
0
0
【Android学习笔记】设置App启动页

先将启动页放到项目资源中,图片一般是1080*1920的jpg。 新建一个activity,如图: 创建成功之后,打开刚刚创建的activity,来进行代码的编写: >>>阅读全文

全部原谅
2分钟前
0
0
什么是React-redux、为什么使用React-redux、怎么使用React-redux

1、什么是React-redux React-redux是用于连接React和Redux的 2、为什么使用React-redux 使用React-redux可以使redux部分代码更简洁更明了,比如组建中需要使用到的数据都在mapStateToProps方...

kimyeongnam
5分钟前
0
0
Spring核心——Stereotype组件与Bean扫描

在注解自动装载中介绍了通过注解(Annotation)自动向Bean中注入其他Bean的方法,本篇将介绍通过注解(Annotation)向容器添加Bean的方法。 Spring的核心容器提供了@Component和@Bean注解来标...

随风溜达的向日葵
5分钟前
0
0
利用世界杯,读懂 Python 装饰器

Python 装饰器是在面试过程高频被问到的问题,装饰器也是一个非常好用的特性, 熟练掌握装饰器会让你的编程思路更加宽广,程序也更加 pythonic。 今天就结合最近的世界杯带大家理解下装饰器。...

猫咪编程
9分钟前
0
0
flink fold example

flink fold例子 import org.apache.flink.api.common.functions.*;import org.apache.flink.streaming.api.datastream.DataStream;import org.apache.flink.streaming.api.environment.S......

coord
10分钟前
0
0
c++ qt 组播总结

每个人都有不同的认知规律和习惯, 有的人喜欢搞一套严密的大理论, 论述起来滔滔不绝, 不管自己懂不懂, 反正读者/听者是没搞懂。 有的人喜欢从实践出发, 没看到代码, 不运行一下, 不看...

backtrackx
14分钟前
0
0
Sublime text2安装json格式化插件SublimePrettyJson[Windows]

一、下载SublimePrettyJson插件包 https://github.com/dzhibas/SublimePrettyJson 二、将下载的文件解压放到在package目录下面 C:\Users\lucky\AppData\Roaming\Sublime Text 3\Packages 每个......

lazy~
14分钟前
0
0
安装vue-cli 报4058错误

1. 4058是网络代理错误。 安装淘宝源修改一下就可以了: npm --registry https://registry.npm.taobao.org info underscore 改为cnpm执行: cnpm install --global vue-cli 安装成功: 试试版...

MrBoyce
15分钟前
0
0
CPU飙升分析

1、top -----看具体的进程 2、top -H -p pid ------该进程的线程 3、printf 0x%x 15248 ------将线程改为16进制 4、jstack 进程...

北极之北
18分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部