内存主要有栈(stack) 堆(heap) 方法区(method area)。
方法区:主要存放静态变量和静态方法(即static修饰的变量和方法),编译后的代码,字符串常量池,以及常量(即final修饰)。
堆:主要用来创建对象,包括对象的变量和方法,主要分为伊甸区,幸存0区,幸存1区,养老区和永久存储区,其中jdk8以后永久区换成了元数据(meta space),永久区本来里面放的事jdk原生的各种class等信息,就是这些永久存在的,但是因为一些特殊原因会造成内存溢出,所以jdk8以后废除了永久区,换成了元数据,那原生的class信息则不再放在堆中而是移到本地内存中(native memory),这样就不容易出现堆内存溢出的问题了
栈:主管java运行,随线程创建销毁。主要存入三类数据:方法的输入输出参数以及方法内的局部变量;栈操作,栈帧(包括类文件和方法)。这里的栈帧其实就是各个方法的代号,就如同唐伯虎在华府被称作9527一样,只是让系统知道方法的执行顺序,不会乱掉。
代码示例
- 定义一个类Computer
- 定义另一个类SxtStu
3.内存执行
(1) 我们首先会通过javac命令来编译类,然后通过java命令来执行这个类。当我们通过java来执行的时候,首先会在方法区中加载当前类的信息,如下图所示:
(2) 开始执行入口参数main方法:
main方法执行的时候,会现在栈中创建一个main方法的栈帧,然后开始执行main方法里的代码。根据上面的代码,第一行创建一个SxtStu对象,这时的结构图如下所示:
可以看到首先在栈中创建一个main方法的栈帧,然后SxtStu stu = new SxtStu();在栈中创建SxtStu类的引用,在堆中创建SxtStu对象,等号相当于讲两者关联起来,如下图:
其中[15db9742]是对象在堆内存中的地址。接着往下面执行,如下图所示:
接下来会执行stu.play();那么就会在栈中 创建play方法的栈帧,然后引用堆内存中的play方法,当main方法执行结束,相应的栈帧也会结束,而堆内存中的对象会通过垃圾回收机制来进行适当的回收。下面文章会讲一下jvm调优。