JVM入门(一)栈和堆
(1)栈
任何软件运行都要开辟内存空间。JVM开辟五个内存区域,分别是栈,堆,方法区,本地方法区,寄存器。
栈存放变量,包括基本类型变量,局部变量,对象的引用(地址)。
栈的存取速度比堆快。由系统自动分配与回收。
栈中的区域是连续的,空间有大小限制,超过阈值抛错:StackOverflowError。
栈帧:每个方法调用都会创建一个栈帧,用于存放局部变量表。方法执行完虚拟机释放空间。
方法递归容易造成栈溢出。
栈溢出代码:
public class Test {
public void test(){
String a;
test();
}
public static void main(String[] args) {
Test t =new Test();
t.test();
}
}
方法调用时创建栈帧,存放变量。因为是递归,方法一直未结束,所以一直创建变量,堆满了栈的空间,所以造成溢出。
(2)堆
堆存放对象和数组,凡是new出来的都放堆中。
栈和堆的关系就是,堆放对象内容,栈放对象的引用地址。
堆超过阈值 就是常见的内存溢出OutOfMemoryError。
堆是动态分配内存,是不连续的内存区域,由Java垃圾回收器管理。
内存溢出代码:
public class Test {
public static void main(String[] args) {
List list = new ArrayList<>();
while (true) {
list.add(1);
}
}
}
VM arguments中配置 -Xss128k 更快发生溢出,大概等1分钟左右。
下面这段代码为什么不会产生内存溢出?
public class Test {
public static void main(String[] args) {
while (true) {
Test t = new Test();
}
}
}
由于while循环中创建的对象未被使用,被标记为垃圾,被垃圾回收器回收了,所以不会造成溢出。
栈和堆的关系图:
体会一下前文提到的 “堆放对象内容,栈放对象的引用地址。”
学完需要记住什么
- 了解栈和堆是JVM的内存区域这一概念
- 栈和堆放什么内容
- 栈和堆溢出异常这个事
- 如何手动书写栈、堆溢出代码