一直对jvm看了又忘,忘了又看的。今天做一个笔记整理存放在这里。
我们先看一下JVM的内存模型图:
上面有5个区,这5个区干嘛用的呢?
我们想象一个场景:
我们有一个class文件,里面有很多的类的定义是不是,类的定义放在什么地方呢?类的定义就放在方法区里面。
程序在运行时会产生很多的对象,比如LinkList等这些对象就存放在堆里面。
一、JAVA栈:
我们的程序在运行时本质上就是启动线程在运行,比如main函数就是一个主线程。一个main主线程可以有很多的子线程。
线程在工作就是执行我们的各种方法。方法里面肯定有我们自己定义了一些局部的变量,比如我们在方法里面new了一个对象,对象肯定是放在堆里面的,但是对堆的引用我们就放在栈里面。那么栈就有问题了,我们一个程序有很多的线程,如果把所有的线程里面的变量存放在一起,肯定有会有变量是重复的,冲突。所有不能放在一起。所以栈里面是分线程来存放的。每一个线程都是自己的栈空间,线程私有的。堆是线程共享的。
栈里面有一个细节:
就是说一个栈空间是以不同的线程区分开来。每个线程有自己栈,每个线程里面又会执行很多的方法,每一个方法对应一个栈帧:
每个方法执行时都会创建一个栈帧(Stack Frame)用语存储局部变量表、操作数栈、动态链接、方法出口等信息。从下图从可以看到,每个线程在执行一个方法时,都意味着有一个栈帧在当前线程对应的栈帧中入栈和出栈。
Java栈也称作虚拟机栈(Java Vitual Machine Stack),也就是我们常常所说的栈,跟C语言的数据段中的栈类似。事实上,Java栈是Java方法执行的内存模型。为什么这么说呢?下面就来解释一下其中的原因。
Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。因此可知,线程当前执行的方法所对应的栈帧必定位于Java栈的顶部。讲到这里,大家就应该会明白为什么 在 使用 递归方法的时候容易导致栈内存溢出的现象了以及为什么栈区的空间不用程序员去管理了(当然在Java中,程序员基本不用关系到内存分配和释放