网上有太多关于java堆,栈的文章,但表述都各不一,有些甚至误导人。今天,我将了解到的,比较正确的来聊一下JVM的内存。
JDK1.8之前,内存大致可划分为方法区、堆、本地方法栈、PC寄存器和java虚拟机栈。
方法区
方法区存放了要加载类的信息、域的信息、方法信息、静态变量(类变量)、final类型的常量。(有关静态与常 量自行去了解)
方法区是全局共享的,在一定条件下也会被GC,当使用的内存超过其允许的大小时,会抛出OutOfMemory。
这块区域对应持久代,默认最小16MB,最大64MB,可通过-XX:PermSize及-XX:MaxPermSize来修改。
常量池属于方法区,顾名思义,就是用来存放常量的,JVM会给每个类型维护一个常量池。
堆
堆用于储存对象实例及数组,可以认为所有通过new创建的对象内存都在此分配。堆中对象所占的内存GC
进行回收。内存大小可通过-Xms(最小内存),-Xmx(最大内存)来修改。堆可分为新生代和旧生代。新生
代又由Eden Space和两块相同大小的Survivor Space构成。堆是全局共享的,new创建的实例对象 比如Person p=new Person(),引用p 分配在栈中,对象Person() 分配在堆中,而实例对象中的成员变量,比如 Person有成员变量int age,Person inner,不管是基本类型age,还是实例变量inner,引用和对象 都存放在堆中。(网上有很多文章对此有误导)
本地方法栈
本地方法栈用于支持native方法的执行。存储了每个native方法调用的状态。
PC寄存器和栈
每个线程都有自己的PC寄存器和栈。PC寄存器占用的可能为CPU寄存器或者操作系统的内存,栈占用的是
操作系统内存。栈为线程私有。方法中局部变量,如果为基本类型,则变量与值存放在栈中,如果为引用
变量时,则栈中存放引用(对象的内存地址),对象存放在堆中。当方法运行完毕时,其对应的栈帧所占
用的内存会自动释放。
当栈空间不足时,会抛出StackOverflowError。可通过-Xss来修改。