这篇文章就以实战的方式看看「静态变量」「实例变量」「局部变量」存放的位置!
首先要搞清楚一个概念,「静态变量」「实例变量」「局部变量」指的是引用本身,而非它们所指向的对象,它们所指向的对象毫无疑问肯定都存放在堆上,关于这个观点更多分析可见 逃逸分析
还需要强调一个点,这里是基于 JDK8 的 HotSpot 虚拟机!!
根据理论知识可以知道:「静态变量」在 JDK7 及以后就存放在 Java 堆中;「实例变量」随着对象实例存放在 Java 堆中;「局部变量」存放在方法栈帧的局部变量表中
首先给出一段测试代码:
public class Test { static class Person { // 静态变量 static ObjectHolder staticObj = new ObjectHolder(); // 实例变量 ObjectHolder instanceObj = new ObjectHolder(); void foo() throws InterruptedException { // 局部变量 ObjectHolder localObj = new ObjectHolder(); // 休眠,不然方法执行完,方法栈帧就会出栈 Thread.sleep(10000000); } } private static class ObjectHolder {} public static void main(String[] args) throws InterruptedException { Person person = new Person(); person.foo(); }}我们先分析一下,按照理论来说,此时 Java 堆中肯定存在 3 个ObjectHolder对象实例,同时staticObj和instanceObj也都在 Java 堆中
下面通过 VisualVM + JProfiler 软件测试一下!!首先用 VisualVM 保存一个 Java 堆的 dump文件,如下所示:
用 JProfiler 打开这个 dump 文件,可以发现在 Java 堆中刚好有 3 个ObjectHolder对象实例,如下图所示:
我们再找找「静态变量」在哪里,在java.lang.Class中可以发现我们定义的静态变量staticObj,而这个静态变量指向的对象实例是0xa87,如下图所示:
继续找「实例变量」在哪里,在com.lfool.myself.Test$Person中可以发现我们定义的实例变量instanceObj,而这个实例变量指向的对象实例是0xc3b,如下图所示:
到此为止,我们找出来的所有内容都存放在 Java 堆中,至于「局部变量」,可以通过 JHSDB 软件在栈中发现,这里就不演示了!!!