本文是何适 JVM 修仙系列第 4 篇,文末有本系列文章汇总。
当面试官问你对象都分配哪里,你把 JVM 内存结构介绍一下然后说分配在堆上,没啥问题,给你打 8 分。如果你还能聊一聊栈上分配,一定是加分项,我想面试官会考虑给你 10 分。
1. 栈上分配理论是什么
将线程私有的不可能被其他线程访问的对象打散分配在栈上,而不是分配在堆上。打散分配意思是将对象的不同属性分别分配给不同的局部变量。
好处
栈上分配速度快。对象销毁不需要垃圾回收,因为方法执行结束后局部变量就销毁了。缺点
栈空间较小,大对象不适合在栈上分配。
2. 逃逸分析如何判断对象是线程私有的呢,就要通过逃逸分析。逃逸指的是逃出当前线程,所以逃逸对象就是可以被其他线程访问的对象,非逃逸对象就是线程私有的对象。
举例:逃逸对象和非逃逸对象
public class StackTest { public static User user1; public static void runAway1() { user1 = new User();// 逃逸对象 } public static void runAway2() { User user2 = new User();// 非逃逸对象 } }3. 栈上分配举例举例:非逃逸对象栈上分配
public class StackTest { public static User user1; public static void runAway1() { user1 = new User();// 逃逸对象 user1.id = 1; user1.name = "user"; } public static void runAway2() { User user2 = new User();// 非逃逸对象 user2.id = 2; user2.name = "user"; } public static void main(String[] args) { for (int i = 0; i <= 99999999; i++) { // runAway1(); runAway2(); } } } class User { int id; String name; }执行代码时设置如下参数:
-server -Xss128K -Xmx100m -Xms100m -XX:+PrintGC -server:server模式下才能设置栈上分配 -Xss128K:栈最大内存 -Xmx100m:堆最大内存 -XX:+PrintGC:打印GC日志代码中创建一个 User 对象需要 16 字节内存,循环 1 亿次,大概需要 1.5GB 空间。
循环执行runAway1();1 亿次,堆内存 100M 小于 1.5G,所以会发生 GC,打印很多 GC 日志。
[GC (Allocation Failure) 25600K->800K(98304K), 0.0009909 secs] [GC (Allocation Failure) 26400K->832K(98304K), 0.0006649 secs] [GC (Allocation Failure) 26432K->776K(98304K), 0.0006009 secs] [GC (Allocation Failure) 26376K->816K(98304K), 0.0009932 secs] [GC (Allocation Failure) 26416K->696K(98304K), 0.0009381 secs] ...循环执行runAway2();1 亿次,由于对象 user2 是线程私有的逃逸对象,执行一次 runAway2()创建一个 User 对象,一次 runAway2()执行完随着局部变量销毁,user2 对象也就销毁了,所以下次执行 runAway2()再创建 user2 对象时还有原来大小的栈空间。循环执行,不会有内存不够的问题,当然也就不会打印出 GC 日志。
4. 总结 参考资料《深入理解 Java 虚拟机(第 2 版) : JVM 高级特性与最佳实践》《实战 Java 虚拟机 : JVM 故障诊断与性能优化》JVM 系列文章汇总【原创】JVM 系列 01 | 开篇 【原创】JVM 系列 02 | Java 虚拟机结构 【原创】JVM 系列 03 | Java 栈—方法是如何调用的?
---来自腾讯云社区的---java进阶架构师
微信扫一扫打赏
支付宝扫一扫打赏