JVM模型的介绍二,接着上一篇我们继续来分享,栈之本地方法栈。
本地方法栈的作用和java虚拟机栈的作用是相类似的;区别在于java虚拟机栈是为java方法服务的,而本地方法栈是为native方法服务的;java虚拟机规范中对本地方法栈中的方法使用的语言、使用方式和数据结构没有强制规范
堆
堆是jvm内存模型中内存空间最大的一块,java堆是被所有线程共享的一块内存区域,在虚拟机启动时随之创建,堆创建的唯一目的就是用来保存对象实例,几乎所有new创建的对象实例都在这里分配内存(随着JIT 编译器的发展与逃逸分析技术的逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化发生,所有的对象都分配在堆上也渐渐变得不是那么“绝对”了)
堆的大小可以通过-Xms和-Xmn两个参数来设置,-Xms为JVM启动时申请的最小内存,默认为操作系统物理内存的1/64但小于1G,-Xmx为JVM可申请的最大内存,默认为物理内存的1/4但小于1G,默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation=来指定这个比列;当空余堆内存大于70%时,JVM会减小heap的大小到-Xms指定的大小,可通过XX:MaxHeapFreeRation=来指定这个比列,对于运行系统,为避免在运行时频繁调整Heap的大小,通常-Xms与-Xmx的值设成一样。
堆也是垃圾收集管理的主要区域,通常所说的垃圾回收主要是回收堆中的垃圾对象,因此堆也被称为GC堆
从垃圾回收的角度上来看,由于现在垃圾收集大多是采用分代收集算法,所以java堆还可以细分为:新生代和老年代;
新生代:程序新创建的对象都是从新生代分配内存,新生代由Eden Space和两块相同大小的Survivor Space(通常又称S0和S1或From和To)构成,可通过-Xmn参数来指定新生代的大小,也可以通过-XX:SurvivorRation来调整Eden Space及SurvivorSpace的大小。
老年代:用于存放经过多次新生代GC仍然存活的对象(默认是15次),例如缓存对象,新建的对象也有可能直接进入老年代,主要有两种情况:
1.大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配。
2.大的数组对象,且数组中无引用外部对象。老年代所占的内存大小为-Xmx对应的值减去-Xmn对应的值。
java堆也会出现内存溢出的情况:如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常
方法区
方法区用于存放已被虚拟机加载的类信息、常量、类变量等数据,它也是所有线程共享的一块内存区域,通常叫它为no-heap(用于与堆区分)或者永生代
永生代也会被GC回收,主要针对常量池回收和类型卸载(反射生成大量的临时class等信息)
常量池用于保存编译器生成的各种字节码和符号引用,具有一定的动态性,里面可以保存编译器生成的常量,运行期间的常量也是可以添加到常量池中的,比如String的intern()方法;
方法区也是会出现内存溢出的情况的:当方法区满时,无法再分配内存空间,就会抛出内存溢出的异常
在java8中已经没有方法区了,取而代之的是元空间metaspace