java 堆溢出:java
在eclipse中测试时,能够在Debug/Run中设置虚拟机参数,好比-xmx 20M 表明虚拟机堆内存大小最大值是20M,-xms是最小堆内存。而后写个死循环测试类不断在List集合中添加对象, 当堆内存超出20M ,会报OutOfMemory异常。框架
虚拟机栈和本地方法栈溢出:eclipse
一个线程中若是,方法的深度超过了虚拟机容许的深度 ,会报StackOverFlow异常,好比递归调用方法。这个异常容易去实现,另外一种是java虚拟机栈在扩展时若是没法申请到内存,则会报OutOfMemory异常。测试
public class Main { private static int count=0; public static void main(String[] args) { // TODO Auto-generated method stub try{ deap(); }catch(Exception ex){ ex.printStackTrace(); } } private static void deap(){ count++; System.out.println(count); deap(); } }
在设置-Xss为1M 和 10M时, 输出的计数变量会差10倍左右,个人理解是虚拟机栈运行时其实就是java方法执行时内存模型,在无止境的递归时会向虚拟机栈中压入栈帧用于存储执行时的操做数,局部变量方法出口等信息。当这块内存满时,就会报栈溢出。
spa
操做系统中系统限制了每个进程的内存上限, 若是规定每一个进程的内存大小上限为1GB, 那么在虚拟机中,方法区内存和堆内存能够经过虚拟机参数设置(xmx和 maxPerSize),虚拟机进程内存减去 堆内存和方法区的总内存,若是忽略计数器和虚拟机自己执行所消耗的内存(这两部分占的内存很小),基本上剩下的内存会被虚拟机栈和本地方法栈瓜分。 每个线程分配到的虚拟机栈内存越大,那么能够建立的线程数量就越少。
操作系统
3.方法区和运行时常量池溢出:线程
方法区内存大小设置能够经过虚拟机参数 -XX:PermSize 和 -XX:MaxPermSize来设置,java 1.6环境中如下代码能够实现方法区常量池内存溢出:
code
public static void main(String[] args) { // TODO Auto-generated method stub int i=0; ArrayList<String> list=new ArrayList<String>(); while(true){ list.add(String.valueOf(i++).intern()); } }
这里String.intern()方法的做用是字符串常量池中若是存在一个等于这个String对象的字符串,则返回引用,不然会将此字符串存入常量池,java 1.6中常量池是分配在永久代内存中,gc几乎不会去回收,因此常量池内存会溢出(1.7 虚拟机中已将字符串常量池从永久代移除), 填充方法区内存可使用gclib来建立大量的类,由于方法区用于存放类Class的相关信息用的,好比类名,访问修饰符,常量池等, Spring,OSGI等主流框架会遇到这样的问题,这类框架都须要加载大量的类,而回收一个类断定条件比较苛刻,在方法区内存分配小时会报OutOfMemoryError:PerGen space异常,即方法区溢出。对象
4.本机内存溢出:
blog
DirectMemory 容量能够经过设置虚拟机参数 -XX:MaxDirectMemorySize来设定,实验方法: 设置了直接内存上限后,不断地经过unsafe类的allocateMemory()方法去申请内存,当达到上限时会报:OutOfMemory异常.
参考链接:
http://lavasoft.blog.51cto.com/62575/25492/