安卓白话文面试(1) —— JVM内存模型?不就是公司的工位布局嘛

18 阅读4分钟

很多面试题第一题就是:“说一下JVM的内存模型”。你要是直接背《深入理解Java虚拟机》里的原文,面试官可能自己都听困了。咱们换个姿势——把JVM想象成一家公司,内存就是公司的办公区,马上你就懂了。


一、先看全局:公司里有哪几类区域?

JVM内存主要分五块:堆、虚拟机栈、本地方法栈、方法区、程序计数器。我们主要关注前三块+方法区,程序计数器太小了,就像每个人手里的“当前做到哪一行”的小便签,暂时忽略。

用公司比喻:

  • 堆(Heap):公司的大仓库,所有员工(线程)都能往里放东西、取东西。
  • 虚拟机栈(VM Stack):每个员工自己的工位+抽屉,别人进不来。
  • 方法区(Method Area):公司的规章制度+员工手册,所有人都能查阅,但基本不改。
  • 本地方法栈:专门用来和外部合作方(比如C语言写的底层系统)打交道的窗口。

二、堆(Heap):公共大仓库

堆是内存里最大的一块,所有线程共享。你new出来的对象、数组,都放在这里。

比喻: 堆就像公司的大仓库。产品部放了一箱样品,销售部也能拿去给客户看;技术部放了一台测试机,运营部也能借用。谁都能存取。

特点:

  • 垃圾回收(GC)主要在这儿干活。没人用的东西,仓库管理员会定期清理。
  • 仓库有大小限制,塞太满就报 OutOfMemoryError(俗称OOM)。比如你不断往ArrayList里add对象,又不释放,仓库就炸了。

面试关键词: 线程共享、GC主要区域、堆溢出(OOM)。


三、栈(VM Stack):每个人的工位

每个线程(可以理解成一个员工)都有自己的栈。栈里放的是栈帧——每个方法调用对应一个栈帧,里面存着局部变量、操作数、方法出口等信息。

比喻: 栈就是你的工位。你干活的时候,桌上会摆一堆资料(局部变量)。你的活儿干完了,就把这堆资料收走,工位腾出来给下一个任务。别人不能坐你的工位,也动不了你桌上的东西。

特点:

  • 栈是线程私有的,天然线程安全(因为别人碰不到)。
  • 递归调用太深,比如 main -> a -> b -> a -> b…… 一直不返回,栈帧叠罗汉,最终工位堆不下,报 StackOverflowError
  • 栈内存一般不大,但存取极快,用完自动释放,不需要GC。

面试关键词: 线程私有、方法调用栈、栈溢出。


四、方法区(Method Area):公司的规章制度

方法区也是线程共享的。它存储类信息(类名、方法、字段)、静态变量、常量池等。在HotSpot虚拟机中,老版本叫“永久代”,新版本叫“元空间”。

比喻: 方法区就是公司的员工手册、报销制度、组织架构图。所有人入职都要看,平时办事也要查。手册里的内容基本不变(类加载后就不改了),偶尔HR会更新一下(比如热部署)。

特点:

  • 线程共享。
  • 如果加载的类太多(比如用了大量动态代理、JSP),也会OOM。
  • JDK 1.8以后,方法区从堆里移到了本地内存,上限更大,但也不是无限。

面试关键词: 类信息、静态变量、常量池、元空间。


五、一张图总结

区域比喻共享?报什么错?
大仓库OOM(堆溢出)
工位否(线程私有)StackOverflowError
方法区员工手册OOM(元空间溢出)

六、面试官爱怎么问?

问: “一个对象从创建到变成垃圾,它在内存里经历了什么?”
答(白话版): 对象出生在堆里,它的类信息放在方法区。被栈里的局部变量引用着,所以活着。没人引用它以后,GC盯上它,在某次回收时把它清理掉。

问: “栈溢出和堆溢出有什么区别?”
答(白话版): 栈溢出是递归太深或方法调用层数太多,工位挤爆了;堆溢出是对象创建太多、内存泄漏,大仓库堆满了。栈溢出一般是程序bug,堆溢出要查内存泄漏。


最后送你一句人话总结:

JVM内存 = 公共仓库(堆)+ 私人工位(栈)+ 员工手册(方法区)。搞清楚谁共享、谁私有、哪里会爆,面试第一关就过了。

汇总导航

安卓白话文面试导航