堆相关的主要就是堆内存异常,不停的创建对象,并且存在应用指向,比如利用List容器存储下来。
/**
* -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\heapdump.hprof
*
* 堆内存溢出
*/
@Test
public void test01(){
List<CustomerObj> lst=new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
lst.add(new CustomerObj());
}
System.out.println("run over");
}
在d盘下生成文件,用D:\ProgramFiles\Java\jdk1.8.0_144\bin\jvisualvm.exe打开,在概要中显示具体的信息
发现CustomerObj实例数过多。
栈相关的异常主要就是栈容量无法容纳新创建的栈帧,比如调用栈过深,
\color{#FF0000}{栈相关的异常主要就是栈容量无法容纳新创建的栈帧,比如调用栈过深,}
栈相关的异常主要就是栈容量无法容纳新创建的栈帧,比如调用栈过深,
或者方法中变量过多,执行方法时分配的栈帧需要更多的容量。
\color{#FF0000}{或者方法中变量过多,执行方法时分配的栈帧需要更多的容量。}
或者方法中变量过多,执行方法时分配的栈帧需要更多的容量。
肯定不会出现栈容量溢出的问题,因为线程开始执行,即为每一个线程分配了线程独享的栈内存
\color{#FF0000}{肯定不会出现栈容量溢出的问题,因为线程开始执行,即为每一个线程分配了线程独享的栈内存}
肯定不会出现栈容量溢出的问题,因为线程开始执行,即为每一个线程分配了线程独享的栈内存
方法调用过深导致的StackOverFlowError,往往就是使用到了递归。
@Test
public void test02(){
stackLeaf();
}
public void stackLeaf(){
stackLeaf();
}
还有一种情况,在
32
位的系统上才能出现
u
n
a
b
l
e
t
o
c
r
e
a
t
e
n
a
t
i
v
e
t
h
r
e
a
d
,
\color{#FF0000}{还有一种情况,在32位的系统上才能出现unable to create native thread,}
还有一种情况,在32位的系统上才能出现unabletocreatenativethread,
因为
32
位机器给每个进程分配的最大空间才为
2
G
,导致没有
\color{#FF0000}{因为32位机器给每个进程分配的最大空间才为2G,导致没有}
因为32位机器给每个进程分配的最大空间才为2G,导致没有
空间为线程创建对应的栈空间
\color{#FF0000}{空间为线程创建对应的栈空间}
空间为线程创建对应的栈空间
方法区和运行常量池
1.7之前常量池在方法区中,1.7后在堆中
/**
* -Xmx20m
*
* 常量池溢出
*/
@Test
public void test04(){
String str="";
List<String> lst=new ArrayList<>();
for (int i = 0; i < 10000; i++) {
str=str+i;
lst.add(str.intern());
}
System.out.println("run over");
}
在1.8中执行得到堆内存溢出。
方法区中存储的是类信息,比如类变量、方法,修饰符。如果采用动态代理的形式大量创建类,也会出现溢出,但是在1.8中不会出现。1.8后PermSize和MaxPermSize参数没有用了,因为已经去掉了永久代,改为元空间,
直接空间导致的内存溢出
/**
* Unsafe分配空间-导致直接内存OutOfMemory
* @throws IllegalAccessException
*/
@Test
public void test06() throws IllegalAccessException {
Field unsafeField= Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true){
unsafe.allocateMemory(1024*1024);
}
}
直接内存溢出和堆内存溢出最大的不同是如果发生了直接内存溢出,heap dump文件中将不会有什么明显的异常。