程序小白在写代码的过程中,经常会不经意间写出发生内存溢出异常的代码。很多时候这类异常如何产生的都傻傻弄不清楚,如果能故意写出让jvm发生内存溢出的代码,有时候看来也并非一件容易的事。最近通过学习《深入理解java虚拟机-JVM高级特性与最佳实践》这本书,终于初步了解了一下java虚拟机的内存模型。本文通过写出使jvm发生内存溢出异常的代码来对自己的学习结果进行总结,同时也提醒自己以后写代码时候不要再跳进这个坑啦。

java的内存管理是由java虚拟机自动进行管理的,并不需要程序员过多的手动干预,这也就导致了初学java的人在不了解java内存模型的情况下也能愉快的进行coding。不过一旦涉及了内存泄露或者内存溢出以及垃圾回收(GC)方面的问题,如果不了解虚拟机是怎么管理内存的,那么排查问题,定位错误地点就显得无从下手了。首先上图看一下java虚拟机运行时数据区是什么样子(图片来源于网络):

大数据培训,云培训,数据挖掘培训,云计算培训,高端软件开发培训,项目经理培训

从上图我们可以获得以下信息:

  1. jvm内存分区可以分为所有线程共享数据区以及线程隔离数据区两部分。这也就是说图中的方法区和堆是由所有的线程共同使用的,而虚拟机栈、本地方法栈、程序计数器则是每个线程独有各自的响应数据区,各线程之间是互不干扰的。

  2. jvm运行时数据区按照功能可分为方法区,堆,虚拟机栈,本地方法栈,程序计数器五个部分。各个部分存储的数据类型不同。 

本文主要讲述如何让JVM发生内存溢出异常,有关JVM内存模型将会在另一篇文章中详细讲解,这里简单介绍各分区的作用:

  1. 堆:各线程共享;存放java对象实例,以及为数组分配的空间也在此处

  2. 虚拟机栈:线程私有;生命周期与线程相同,描述java方法执行的内存模型,每个方法在执行时创建栈帧,栈帧存储局部变量表、操作数栈、动态链接、返回地址(方法出口)等信息

  3. 本地方法栈:和虚拟机栈功能类似,线程私有;为虚拟机使用的Native方法提供服务

  4. 方法区:各线程共享;存储已被虚拟机加载的类的信息、final声明的常量,static修饰的静态变量,以及编译器编译后的java代码等数据(jdk7以后把常量池移到了堆中

  5. 程序计数器:线程私有;可以看做是当前线程所执行程序的字节码的行号指示器

在jvm规范中,除了程序计数器内存区域没有规定任何内存溢出异常情形外,其他四个内存区域都会有相应的内存溢出异常发生的可能,所以jvm内存溢出异常发生在不同的内存区域具有不同的异常发生原因,知道一内存异常产生的位置,对于定位错误地点就很有指向性了。

下面就通过实例来展示,如何通过代码指定让不同的内存区域发生内存溢出异常。

一、java堆发生内存溢出:

java堆是用来存储对象实例以及数组的,使java堆发生内存溢出的要旨是:

  • 不断创建对象

  • 保证对象存活,不会被垃圾收集器回收

java虚拟机的内存大小是可以人为设置的,通过设置限制内存大小,可以很方便的实现内存溢出,节约了时间。

设置java堆内存大小的虚拟机参数为:-Xms堆的初始大小 -Xmx堆可扩展的最大值

大数据培训,云培训,数据挖掘培训,云计算培训,高端软件开发培训,项目经理培训 

延伸阅读

学习是年轻人改变自己的最好方式-Java培训,做最负责任的教育,学习改变命运,软件学习,再就业,大学生如何就业,帮大学生找到好工作,lphotoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训学习是年轻人改变自己的最好方式