Java程序是运行在JVM(Java虚拟机)上的,因此Java的内存分配是在JVM中进行的,JVM是内存分配的基础和前提。Java程序的运行会涉及以下的内存区域:
- 寄存器:JVM内部虚拟寄存器,存取速度非常快,程序不可控制。
- 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中。
- 堆:存放new出来的对象,注意创建出来的对象只包含各自的成员变量,不包括成员方法。
- 常量池:存放常量,如基本类型的包装类(Integer、Short)和String,注意常量池位于堆中。
下图表示了程序大致的内存分配情况:
下面通过具体的代码说明程序在内存中是如何运行的
5. 首先JVM找到main方法作为入口,执行第一句代码后,在堆中创建一个Test实例,并在栈中分配一块内存,存放指向堆中实例的引用变量(x0110925),该引用变量表示的是堆内存中对象的地址。
6. 创建一个int型的变量date,由于是基本类型,直接在栈中存放date对应的值9。
7. 在堆内存中创建两个Person类的实例p1、p2,在栈中存放了指向各自对象的引用变量,表示实例对象的地址。在堆内存中创建的实例对象还包含各自的成员变量。
8. 调用test对象的change1方法,并以date作为参数传入,此时JVM会为change1方法在栈中分配相应的内存,并将该方法的局部变量i存放在栈内存中,将date的值赋给i,因此i的值为9。
9. 执行change1方法中的代码,将i的值修改为1234。
6.change1方法执行完毕,释放其占用的栈内存。
10. 调用test对象的change2方法,JVM为该方法分配栈内存,将p1作为实参传入,并将局部变量p入栈。由于是引用类型,p中保存的同样是对象的地下。此时p和p1指向的是堆中的同一个对象。
11. 调用test实例的change3方法,传入参数p2,JVM会为变量b在栈中分配空间,并将p2的地址赋给b,此时p2和p指向同一个对象,再调用实例b的setJobNumber方法,其实就是调用p2指向的对象的setJobNumber方法。
更详细的动画视频讲解地址 https://www.bilibili.com/video/BV1Pt4y147cs/