【Java虚拟机】内存溢出实战
在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(下文称OOM)异常的可能,本节将通过若干实例来验证异常发生的场景。
测试异常需要设置虚拟机的启动参数,以MyEclipse工具为例,修改如下:Run——>Run Configurations;(修改的参数在代码顶部注释中,这些参数将对实验的结果有直接影响)
Java堆溢出
Java堆用于存储对象实例,只要不断地创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import
java.util.ArrayList;
import
java.util.List;
/**
* -Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
* 将堆最小值参数-Xms与最大值-Xmx参数设置为一样即可避免堆自动扩展,
* @author Vanguard
*/ public
class
TestGC {
static
class
OOMObject{
}
public
static
void
main(String[] args) {
List
new
ArrayList<>();
while
(
true
){
list.add(
new
OOMObject());
}
} } |
OutOfMemoryError后紧跟着Java heap space提示堆溢出。
栈溢出
由于在HotSpot虚拟机中并不区分虚拟机栈和本地方法栈,因此,对于HotSpot来说,虽然-Xoss参数(设置本地方法栈大小)存在,但实际上是无效的,栈容量只由-Xss参数设定。
关于虚拟机栈和本地方法栈,在Java虚拟机规范中描述了两种异常:
- 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
- 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /**
* -Xss128k
* @author Vanguard
*/ public
class
JavaVMStackSOF {
private
int
stackLength=
1
;
public
void
stackLeak(){
stackLength++;
stackLeak();
}
public
static
void
main(String[] args) {
JavaVMStackSOF oom =
new
JavaVMStackSOF();
try
{
oom.stackLeak();
}
catch
(Throwable e){
System.out.println(
"stack length:"
+oom.stackLength);
throw
e;
}
} } |
方法区溢出
运行时常量池是方法区的一部分,因此这两个区域的溢出测试就放在一起进行。
String.intern()是一个Native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。对于这些区域的测试,基本的思路是运行时产生大量的类去填满方法区,直到溢出。
在实际应用中,当前的很多主流框架,如Spring、Hibernate,在对类进行增强时都会用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成的Class可以加载入内存,若内存不足则引发异常。
【【Java虚拟机】内存溢出实战】转自:http://www.yexiaoquan.com/article/17061301.html
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘