先说结论
主要包括程序计数器、虚拟机栈、本地方法栈、堆和方法区。
线程私有区域
程序计数器、虚拟机栈和本地方法栈随线程创建和销毁。虚拟机栈以栈帧为单位保存局部变量表、操作数栈和返回地址等信息。
线程共享区域
堆与方法区由多个线程共享。堆是对象分配和垃圾回收的主要区域,方法区保存类元数据、运行时常量池等信息。
常见异常
递归过深可能产生 StackOverflowError;对象无法分配可能产生 Java heap space;类元数据过多可能导致 Metaspace OOM。
一次方法调用如何执行
调用方法时创建栈帧,参数和局部变量进入局部变量表,字节码借助操作数栈完成计算。方法正常返回或抛出未捕获异常时栈帧弹出。局部变量可能保存堆对象的引用,但引用变量和对象实体不是同一回事。
常见问题
追问 1:堆和栈最本质的区别是什么?
栈服务线程的方法调用,生命周期与栈帧一致;堆服务对象存储,由线程共享并受 GC 管理。“栈快堆慢”不是本质定义。
追问 2:元空间会 OOM 吗?
会。大量动态生成类、类加载器泄漏或上限过小都可能导致 Metaspace OOM,应分析类数量与 ClassLoader 生命周期。
追问 3:对象一定在堆上吗?
语义上对象通常由堆管理,但 JIT 可对未逃逸对象做标量替换,甚至消除分配,不能机械回答“一定”。