标签:
java 堆溢出:
在eclipse中测试时,可以在Debug/Run中设置虚拟机参数,比如-xmx 20M 代表虚拟机堆内存大小最大值是20M,-xms是最小堆内存。然后写个死循环测试类不断在List集合中添加对象, 当堆内存超出20M ,会报OutOfMemory异常。
虚拟机栈和本地方法栈溢出:
一个线程中如果,方法的深度超过了虚拟机允许的深度 ,会报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方法执行时内存模型,在无止境的递归时会向虚拟机栈中压入栈帧用于存储执行时的操作数,局部变量方法出口等信息。当这块内存满时,就会报栈溢出。
操作系统中系统限制了每一个进程的内存上限, 如果规定每个进程的内存大小上限为1GB, 那么在虚拟机中,方法区内存和堆内存可以通过虚拟机参数设置(xmx和 maxPerSize),虚拟机进程内存减去 堆内存和方法区的总内存,如果忽略计数器和虚拟机本身执行所消耗的内存(这两部分占的内存很小),基本上剩下的内存会被虚拟机栈和本地方法栈瓜分。 每一个线程分配到的虚拟机栈内存越大,那么可以创建的线程数量就越少。
3.方法区和运行时常量池溢出:
方法区内存大小设置可以通过虚拟机参数 -XX:PermSize 和 -XX:MaxPermSize来设置,java 1.6环境中以下代码可以实现方法区常量池内存溢出:
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.本机内存溢出:
DirectMemory 容量可以通过设置虚拟机参数 -XX:MaxDirectMemorySize来设定,实验方法: 设置了直接内存上限后,不断地通过unsafe类的allocateMemory()方法去申请内存,当达到上限时会报:OutOfMemory异常.
参考连接:
http://lavasoft.blog.51cto.com/62575/25492/
标签:
原文地址:http://my.oschina.net/u/272065/blog/508635