设置Java堆大小: -Xms:设置最小堆空间,-Xmx:设置最大堆空间
Java堆还可以细分为新生代和老年代,而新生代又可以细分为Eden区,From Survivor区,To Survivor区等
新生代
主要用来存放刚创建的对象(new),新生代的内存空间占用堆的1/3。由于对象频繁创建,会导致新生代频繁触发MiniorGC 进行垃圾回收。
新生代可以分为Eden区(伊甸园),From Survivor区,To Survivor区,三者的大小比是8:1:1,可以通过参数-XX:SurvivorRatio=8
设置。
-
Eden区: Java对象出生地(并不是每个new对象都存放在这里,较大的对象可能直接到老年代)
-
From区:第一次gc,存活下来的对象所在的区,也是每次gc对象要移动的区。
-
To区:和from区作用一样,就是from区和to区两个空间不断移动存活的对象
下面我们说下三个区的关联
大多数情况下,对象在新生代的Eden区中分配,当Eden区没用足够空间进行分配时,虚拟机将发起一次Minor GC。而经过这次Minor GC后仍然存活的对象将全部进入To区,再次GC的时候eden和To区中存活的对象又被复制进入到From区。就这样在每次Minor GC的时候存活的对象反复在From区和To区来回复制,每复制一次对象的年龄就+1,当年龄达到约定的年龄(默认15,-XX:MaxTenuringThreshold=15
)之后就会进入老年代。
为什么要有两个Survivor区?
由上面的流程知道,Survivor区是用来存活每次经历Minor GC的对象,经历15次之后到达老年代的对象就变少了。如果没有这个区,每次经历Minor GC后直接被送到老年代,老年代很快就被填满了,然后触发Major GC,而Major GC的代价远远大于Minor GC。
每次两个区来回复制存活对象是复制算法,这样解决了碎片化。
老年代
老年代的内存空间占用堆的2/3, 存放一些生命周期较长的对象,像新生代晋升过来的或者较大对象。如果老年代内存不足将进行Major GC(采用标记-清除算法),如果回收之后还是不足就会就会抛出OOM(Out of Memory)异常了。
永久代
在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。
为什么1.8改成元空间?
1. 字符串常量池存在于永久代中,在大量使用字符串的情况下,非常容易出现OOM的异常。
2. JVM加载的class的总数,方法的大小等都很难确定,因此对永久代大小的指定难以确定。太小的永久代容易导致永久代内存溢出,太大的永久代则容易导致虚拟机内存紧张。
3. 永久代对GC的回收带来了不必要的复杂度,而且回收率偏低。
解释:
新生代GC(Minor GC):发生在新生代的垃圾收集动作,因为Java对象大多都具有朝生夕死的特性,所以Minor GC很频繁,一般回收速度也比较快。
老年代GC(Major GC/Full GC):发生在老年代的GC,出现Major GC 经常会伴有至少一次Minor GC(不是一定),Major GC的速度一般比Minor GC慢10倍以上。
关注不迷路
除了虚拟机系列 还有MySQL高级相关更多内容,如事务,锁,MVCC,读写分离,分库分表等还在持续更新中,欢迎关注催更。
我是阿纪,用输出倒逼输入而持续学习,持续分享技术系列文章,以及全网值得收藏好文,欢迎关注公众号,做一个持续成长的技术人。