• 虚拟机系列:JVM 运行时堆内存如何分代


    对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内在中最大的一块。Java堆是被所有线程共享的一块内在区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。虚拟机规范中的描述是:所有类的实例与数组对象都要在堆中分配。但是随着JIT编译器的发展与逃逸分析技术的逐渐成熟,栈上分配,标量替换优化技术导致一些变化,所有对象并不都分配在堆上

    设置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,读写分离,分库分表等还在持续更新中,欢迎关注催更。

    我是阿纪,用输出倒逼输入而持续学习,持续分享技术系列文章,以及全网值得收藏好文,欢迎关注公众号,做一个持续成长的技术人。

     

  • 相关阅读:
    手头上的几本关于实现程序设计语言的书
    Ubuntu 16.04 搭建KVM环境
    调用RESTful GET方法
    Ubuntu 16.04 安装Docker
    Ubuntu 16.04安装Java 8
    SecureCRT 多个会话显示在同一窗口
    Ubuntu 16.04 安装Maven3.3.9
    Python标准类型的分类
    Ubuntu 16.04 更改apt源
    LVM术语及相互关系
  • 原文地址:https://www.cnblogs.com/sunjiguang/p/15765601.html
Copyright © 2020-2023  润新知