sas java 虚拟机异常_java虚拟机之常见的异常

本文详细分析了Java中的几种内存溢出情况,包括JAVA堆溢出、虚拟机栈和本地方法栈溢出、方法区及运行时常量池溢出。通过示例代码解释了如何触发这些异常,以及JVM参数如何影响内存分配。同时,探讨了`String.intern()`方法在不同JDK版本中的行为差异及其对内存的影响。
摘要由CSDN通过智能技术生成

1、JAVA堆溢出

public class HeapOOM {

HeapOOM[] testlist= new HeapOOM[100000];

public static void main(String[] args) {

List list= new ArrayList();

while(true){

list.add(new HeapOOM());

}

}

}

2、虚拟机栈和本地方法栈溢出(-Xss:栈内存容量)

两种异常:

如果线程请求的深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

单线程时栈溢出:

public class StackOverflow {

private int stackLength = 1;

public void stackLeak(){

stackLength++;

stackLeak();

}

public static void main(String[] args) throws Throwable {

StackOverflow stackOverflowError = new StackOverflow();

try {

stackOverflowError.stackLeak();

}catch (Throwable e){

System.out.println("stack 深度:"+stackOverflowError.stackLength);

throw e;

}

}

}

多线程下的栈溢出:

通过不断建立线程的方式可以产生内存溢出异常。在这种情况下,为每个线程的栈分配的内存越大,越容易产生内存溢出异常。

原因是:操作系统分配给每个进程的内存是有限制的,譬如32位的Windows限制为2GB。虚拟机提供了参数来控制Java堆和方法区的两部分内存的最大值。剩余的内存为2GB减去Xmx(最大堆容量),再减去MaxPermSize(最大方法区容量)

public class StackOverThread {

private void donnotStop(){

while (true){

donnotStop();

}

}

public void stackLeakByThread(){

while (true){

Thread thread = new Thread(new Runnable() {

public void run() {

donnotStop();

}

});

thread.start();

}

}

public static void main(String[] args) {

StackOverThread stackOverThread = new StackOverThread();

stackOverThread.stackLeakByThread();

}

}

3、方法区和运行时常量池溢出

String.intern():如果字符串常量池中已经包含了一个等于此String对象的字符串,则返回代表这个字符串的String对象,否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

-XX:PermSize和 -XX:MaxPermSize限制方法区大小,从而间接限制其中常量池的内容。

public class RuntimeConstantPool {

public static void main(String[] args) {

List list = new LinkedList();

int i = 0;

while (true){

list.add(String.valueOf(i++).intern());

}

}

}

报错:  Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

at java.lang.String.intern(Native Method)

at com.yhq.chapter1.RuntimeConstantPool.main(RuntimeConstantPool.java:12)

public class RuntimeConstantPool2 {

public static void main(String[] args) {

String str1 = new StringBuilder("计算机").append("软件").toString();

System.out.println(str1.intern() == str1);

String str2 = new StringBuilder("ja").append("va").toString();

System.out.println(str2.intern() == str2);

}

}

在jdk1.6中会得到两个false,在jdk1.7中会得到一个true和一个false。

在jdk1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串实例的引用,而由StringBuilder创建的字符串在Java堆上,所以必然不是同一个引用,将返回false。

在jdk1.7中,intern()方法实现不会复制实例,只是在常量池中记录首次出现的实例引用,因此intern()返回的引用和由StringBuilder创建的那个字符串实例是同一个。对于str2返回的是false是因为“java”这个字符串在执行StringBuilder.toString()之前已经出现过,字符串常量池中已经有它的引用,不符合首次出现原则,此时intern()返回的是字符串常量池中的引用,而由StringBuilder创建的字符串在Java堆上,所以必然不是同一个引用,将返回false。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值