关于GC之一-JVM内存划分

JVM内存划分

JVM内存的划分网上已经有一大堆,这里根据自己的理解,做一些记录。(大部分知识来源于深入理解JVM虚拟机、Java性能权威指南、Plumbr Handbook Java GC,推荐可以都看看)。
总体来说,JVM的内存分为堆及堆外,堆是javaer关注的重点,而在经历过一些问题之后,意识到堆外也需要多了解。

内存区域划分可以参考这里:
http://gityuan.com/2016/01/09/java-memory/

在这里借鉴其中的两幅图:


关于GC之一-JVM内存划分_第1张图片
图片发自App
关于GC之一-JVM内存划分_第2张图片
图片发自App

堆外空间

jdk1.8之后,perm区变迁为metaspace。metaspace也是一块堆外空间。

metaspace,在hotspot虚拟机中可以对应为方法区。笨神写过一篇相关的文章,我就不班门弄斧了。可以简单理解为这里存储了编译后的类信息,包含常量池等数据。

参考笨神的文章: http://lovestblog.cn/blog/2016/10/29/metaspace/

其默认大小为1g,对应的常用jvm参数为-XX:MetaspaceSize 和-XX:MaxMetaspaceSize设定大小,但如果不指定MaxMetaspaceSize的话,Metaspace的大小仅受限于native memory的剩余大小。

还有一块不在JVM内存管理范畴之内,即直接内存。为了减少GC、提高数据交换性能引入的,一般在NIO时使用,通过DirectByteBuffer来管理,详见另一偏《堆外内存》的笔记。

堆空间

堆的整体大小指定可以通过-xms和-xmx指定对应的最大最小值。不过对于一般的应用场景,都建议这两个指定的参数值设置相同的值,避免需要频繁扩容,产生过多fgc。

堆空间主要分为两大块,年轻代(young)和老年代(old),其中年轻代又划分为三块区域,eden、survivor0(又称为from)、survivor1(又称为to)。默认年轻代占堆空间的3/8,而年轻代中survivor区域默认占整个年轻代的20%,survivor0和survivor1各占10%,剩余的80%空间给到了eden。详见下图:

关于GC之一-JVM内存划分_第3张图片
1353728416_1655.jpg

对象分配

对象的分配主要在eden区域,当然也不排除eden区域内空间不够时,有大对象直接分配在old区域,这种情况下需要关注大对象的生存周期,避免频繁出现fgc。

eden区域的内存分配是多线程的,但是对于吞吐量比较大的系统,有时一秒钟可以分配上g的内存,如果要在其中再加入锁或者同步,会导致对象的内存分配效率很低。所以jvm引入了tlab,即thread local allocate buffer。它是线程级别的,每个线程在创建的时候都会在堆中分配一块专属的内存区域,用于线程内部的对象内存分配。如果TLAB空间耗完,再需要分配内存时,就需要为线程扩容TLAB。

你可能感兴趣的:(关于GC之一-JVM内存划分)