【JVM】内存模型全套面试题拆解,吃透稳拿offer
大家好我是程序员二叉。简介本文整理JVM运行时内存分区全套面试考点包含内存区域划分、String s new String(abc)内存分配流程、堆分代设计原理、Survivor两区作用、方法区与元空间对比、永久代淘汰原因、直接内存特性等高频问题。欢迎点赞收藏关注。一、JVM运行时内存模型分区JVM运行时数据区分为线程私有、线程共享两大块直接决定内存分配与GC范围。1. 线程私有每个线程独立线程销毁内存释放程序计数器记录线程当前执行的字节码指令行号唯一一个不会发生OOM的内存区域。虚拟机栈每个方法执行时创建栈帧存放局部变量表、操作数栈、动态链接、方法返回地址局部变量包含基本数据类型、对象引用地址。栈深度超限抛出StackOverflowError。本地方法栈专门为JNInative本地方法提供运行内存结构与虚拟机栈一致。2. 线程共享JVM启动分配全局共用Java堆(Heap)所有对象实例、数组的唯一分配区域GC回收的核心区域可通过-Xmx/-Xms调节最大最小堆内存。方法区JDK8后实现为元空间Metaspace存储类元数据、静态变量、运行时常量池、JIT编译缓存等。运行时常量池属于方法区的子区域存放编译期字面量、符号引用运行期也可动态放入常量。补充直接内存不属于JVM运行时数据区是操作系统物理本地内存NIO框架大量使用。二、String s new String(“abc”) 各部件对应内存区域类加载阶段字符串字面量abc存入方法区的运行时常量池执行new String()在Java堆中创建一个String实例对象虚拟机栈的局部变量表生成引用变量s栈内只存地址堆内String对象内部的value字符数组指向常量池里的abc内存归属总结虚拟机栈引用变量sJava堆new出来的String实例对象方法区常量字符串abc三、堆为什么划分新生代、老年代默认比例1. 分代设计的原因对象生命周期两极分化绝大多数对象朝生夕死少量对象长期存活适配不同GC算法提升性能新生代存活对象少使用复制算法GC速度极快老年代存活对象多使用标记清除/标记整理减少复制开销避免每次GC扫描整个堆降低全局停顿时间2. 默认内存占比新生代 : 老年代 1 : 2新生代占整个堆内存1/3老年代占2/3。四、Eden、From、To Survivor作用为什么设置两块Survivor1. 各区基础作用Eden区所有新创建对象优先分配在此占新生代80%From(S0) Survivor上一次Minor GC筛选出的存活对象存放区To(S1) Survivor本次Minor GC的存活对象复制目标空白区新生代内部默认比例Eden : From : To 8 : 1 : 12. 必须两个Survivor的核心原因采用复制回收算法解决内存碎片问题同一时间永远只用Eden 一块Survivor另一块保持空白Minor GC时EdenFrom存活对象全部拷贝到空白To区拷贝完成直接清空Eden和From互换From/To标识全程不会产生内存碎片回收效率远高于单Survivor如果只设置一块Survivor存活对象挪走后会产生大量零散空闲块内存碎片化严重。五、方法区 / 元空间 作用与存储内容1. 核心作用线程共享内存区域用于存储所有被类加载器加载后的类元信息支撑类实例化、方法调用、静态变量访问。2. 存放内容类基础元数据类名、父类、接口、访问修饰符、字段/方法描述static静态变量、静态常量运行时常量池字符串常量、数字常量、符号引用构造方法、普通方法字节码JIT即时编译器编译后的本地机器码缓存六、永久代(PermGen)和元空间(Metaspace)区别JDK8废弃永久代原因1. 对比表格对比项永久代JDK7及之前元空间JDK8内存位置堆内存内部划分操作系统本地物理内存大小限制固定值必须配置-XX:MaxPermSize默认无上限仅受整机物理内存约束OOM概率极易出现PermGen OOM大幅降低内存溢出风险GC机制Full GC才会回收类元数据回收滞后自动阈值扩容垃圾回收更及时2. JDK8废弃永久代改用元空间的理由永久代大小固定动态加载大量类Spring、MyBatis、动态代理极易触发OOM永久代调参门槛高运维很难预估所需内存大小HotSpot永久代与JRockit、IBM J9虚拟机内存模型不统一元空间统一架构把类元数据移到本地内存堆内存压力降低GC压力减小简化内存模型移除永久代相关复杂逻辑七、直接内存是什么是否会发生OOM1. 直接内存定义不属于JVM堆、不属于运行时五大内存区直接向操作系统申请的物理内存NIO中ByteBuffer.allocateDirect()分配使用零拷贝优化IO传输性能读写数据减少用户态与内核态之间的内存拷贝速度优于堆内缓冲区2. 会不会OOM会出现直接内存溢出不受-Xmx堆最大值约束但整机物理内存有上限大量分配DirectBuffer且不手动释放内存持续占用耗尽系统内存抛出OOM可通过启动参数-XX:MaxDirectMemorySize手动限制直接内存最大容量总结JVM内存分线程私有程序计数器、虚拟机栈、本地方法栈 共享堆、方法区 直接内存new字符串栈存引用、堆存对象、方法区存常量字面量堆分代是为匹配对象生命周期优化GC效率新老默认1:2双Survivor依靠复制算法消除内存碎片新生代默认8:1:1方法区存类元数据、静态变量、常量池JDK8元空间替换堆内永久代直接内存提升IO速度无堆上限但物理内存有限依然会OOM