【摘要】 java中内存分布说的明明白白
一、堆内内存
1.1 年轻代-Young Generation
-
存放的是new 生成的对象
-
年轻代是为了尽可能快速的回收掉那些生命周期短的对象
-
Eden
-
大部分对象在Eden区中生成
-
当Eden区满时,会做一次young gc, 依然存活的对象将被复制到Survivor区, 当一个Survivor 区满时, 此区的存活对象将被复制到另外一个Survivor区
-
Survivor(通常2个)
-
当两个 Survivor 区 都满时, 从第一个Survivor 区 被复制过来 且 依旧存活的 对象,超过一定年龄的会被复制到 老年代(Tenured)
-
Survivor 的两个区是对称的, 没有先后关系, 所有同一个区中可能同时存在从Eden复制过来的对象 和 从前一个 Survivor 复制过来的对象。
-
把age大于-XX:MaxTenuringThreshold的对象晋升到老年代;(对象每在Survivor区熬过一次,其age就增加一岁);
1.2 老年代 (Old Generation)
-
存放了在年轻代中经历了N次垃圾回收后仍存活的对象, 是一些生命周期较长的对象.
-
存放那些创建的时候占用空间比较大的对象,这些对象不经历eden,直接进入老年代,大对象(大小大于-XX:PretenureSizeThreshold的对象)
1.3 元数据(Meta space)
-
存放类的数据
-
存放静态文件, 如静态类和方法等。持久代对垃圾回收没有显著影响, 但是有些应用可能动态生成或者调用一些class, 比如Hibernate, Mybatis 等, 此时需要设置一个较大的持久代空间来存放这些运行过程中新增的类。
-
设置持久代大小参数: -XX:MetaspaceSize, -XX:MaxMetaspaceSize
1.4 总结
-
-XX:NewRatio 设置新老年代比例,如-XX:NewRatio=5 代表 新老年代比例为1:5,新生代占用堆内存的1/6,老年代占用5/6;
-
-XX:SurvivorRatio 设置新生代中eden和两个2个Survivo区域大小的比例,如-XX:SurvivorRatio=8,则eden:s1:s2=8:1:1,默认比例就是为8:1:1.
二、堆外内存
-
用DirectBufferByteBuffer.allocateDirect(size)
-
用JNI写java的c/c++扩展,在扩展里不牵扯jvm自己向系统搞内存出来。
-
减少了垃圾回收因为垃圾回收会暂停其他的工作。
-
加快了复制的速度堆内在flush到远程时,会先复制到直接内存(非堆内存),然后在发送;而堆外内存相当于省略掉了这个工作。
三、垃圾回收
3.1 垃圾回收(GC)
-
Minor GC
-
一般当新对象生成并且在Eden申请空间失败时就会触发MinorGC, 对Eden区域进行GC, 清除非存活对象, 并且把尚存活的对象移动到Survivor区, 然后整理两个Survivor区。
-
该方式的GC是对年轻代的Eden区进行,不会影响到年老代。
-
由于大部分对象是从Eden区开始的, 所以Eden区的GC会很频繁。
-
Major GC / Full GC
-
老年代(Tenured) 被写满
-
持久代(Permanent) 被写满
-
System.gc() 被显示调用
-
上一次GC之后Heap 的各域分配策略动态变化
-
对整个堆进行整理。
-
所消耗的时间较长, 所以要尽量减少 Full GC 的次数