JAVA的JVM内存空间分为三个重要区域:堆、栈和方法区

栈区
线程私有。每个线程有自己的栈区,栈中只保存了方法中的局部变量数据,包括了局部变量的基础数据类型和对象实例的引用。
- 更具体地说,在线程私有区的虚拟机栈中,会在每个 Java 方法执行的同时创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息
栈中数据都是私有的,其他栈不可以访问
通过下面代码,观察栈中是否有分配对象内存
public class ClassA{
public int arg;
public ClassA(int arg) {
this.arg = arg;
}
@Override
protected void finalize() throws Throwable {
System.out.println("对象即将被销毁: " + this + "; arg = " + arg);
super.finalize();
}
}
public class TestCase1 {
public static ClassA getClassA(int arg) {
ClassA a = new ClassA(arg);
System.out.println("getA() 方法内:" + a);
return a;
}
public static void foo() {
ClassA a = new ClassA(2);
System.out.println("foo() 方法内:" + a);
}
public static void main(String[] args) {
ClassA classA = getClassA(1);
System.out.println("main() 方法内:" + classA);
foo();
}
}
结果:
getA() 方法内:bean.ClassA@2503dbd3
main() 方法内:bean.ClassA@2503dbd3
foo() 方法内:bean.ClassA@4b67cf4d
没有调用finalize方法,可以说明foo()实例化的对象没有随着foo()方法的出栈而销毁,即foo()方法内实例化的局部对象并没有分配内存在栈上
堆区:
JVM中有句关于堆的解释
The heap is the runtime data area from which memory for all class instances and arrays is allocated。
堆是所有的对象实例以及数组分配内存的运行时数据区域。
所有线程共享。存储了全部的对象实例,即所有的对象都在这里分配内存。而每个实例都有一个与之对应的class信息存到方法区中。
堆中存放的对象本身,包括了成员变量和局部变量,除此外还有成员变量的引用和成员变量的基本数据类型。
方法区:
所有线程共享。用于存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
虚拟机把它当成永久代来进行垃圾回收。但很难确定永久代的大小,因为它受到很多因素影响,并且每次 Full GC 之后永久代的大小都会改变,所以经常会抛出 OutOfMemoryError 异常。为了更容易管理方法区,从 JDK 1.8 开始,移除永久代,并把方法区移至元空间,它位于本地内存中,而不是虚拟机内存中。
网友评论