JVM内存管理详解

JVM内存结构

JVM在运行java程序时将运行时数据划分成几种不同格式的数据,分别存储在不同的区域里,这些数据又统一称为运行时数据,而java虚拟机规范又将java运行时数据划分为以下6种.

  • pc寄存器
  • 严格来说这是一种数据结构,它用于保存当前正常执行的程序的内存地址,同时java程序是多线程执行的,所以需要一个记录员记录下每一个线程执行到哪一条指令.

  • 栈区
  • 栈总是和线程关联在一起的,每创建一个线程jvm就会为这个线程创建一个对应的java栈,而每个java栈中又会有多个栈帧,另外有一点需要注意,java栈与java线程是对应起来的,这个数据不是线程共享的,所以我们不用关心它的数据一致性.

  • 堆区
  • 堆区是存放java对象的地方,也是开发人员最应该关注的区域,堆区中所有对象都被线程共享,访问时需要关注线程同步问题.

  • 方法区
  • 方法区是存放类结构的地方,当class被加载到jvm时会被存放在不同的数据结构中,而其常量,域,方法数据,方法体,构造函数等都存放在此区域.

  • 运行时常量
  • 包括存放编译期数字常量,方法或者域引用,它是方法区一部分,其存储也受方法区规范约束,如果常量池无法分配,也会出现OOM异常.

  • 本地方法栈
  • 本地方法栈是为jvm运行native方法准备的空间,由于很多native方法使用c实现,所以也可以称作c栈.

堆区划分

我们程序员最关心的还是Heap区,而对于JVM对堆区的管理又比较复杂,首先我们先看看堆区如何划分.

  • Young区
  • Young区分Eden区与两个Survivor区,其中所有全创建的对象都存在Eden区,当Eden区满后会触发Minor GC将Eden区仍然存活的对象复制到Survivor区中,另一个Survivor区中存活的对象也复制到这个Survivor区中,并且保证始终有一个Survivor区是空的.

  • Old区
  • Old区存放的是Young区的Survivor满后触发Minor GC仍存活的对象,当Eden区满后会将对象存至Survivor区,如果Survivor区仍存不下这些对象,将会把这些对象直接存放至Old区,如果Old区也满了,则会触发Full GC回收整个内存.

  • Perm区
  • PermGen区存放java中的类与类加载器,此外,对以上各区大小也有一定的设置建议,如Young区为整个堆区的1/4,而Survivor区一般为Young区的1/8.

GC收集器

明白堆区如果划分后,我们还需要知道内存是如何分配与回收的,这里我们详细了解下jvm如果回收垃圾对象,这里我们有三种常用垃圾收集算法.

  • Serial Collector
  • jvm在client模式下默认GC方式,可以通过JVM参数-XX:+UseSerialGC来指定使用该算法,此时GC是串行,这些动作都是单线程完成,而此时应用程序会全部停止.
    其规则很简单,若每次晋升对象都超过了Old区的剩余空间,则说明当前Old区空间已经 不能满足新对象所占用的空间大小,只有触发FullGC才能获得更多内存空间
    优点:适合内存有限的情况
    缺点:由于使用单线程,回收较慢

  • Parallel Collector
  • 根据Minor GC与Full GC的不同分为三种,ParNewGC ParallelGC ParallelOldGC

    ParNewGC
    使用参数-XX:+UseParNewGC开启,它的对象分配与回收策略与Serial Collector类似,只是回收的线程不是单线程的,而是多线程回收.

    ParallelGC
    Server默认的GC方式,可以使用-XX:+UseParallelGC开启,并且回收的线程数可以使用-XX:ParallelGCThreads来指定,如果cpu的核数小于8,线程数可以设置与核数一样,如果大于8,一般使用3+(cpu*5)/8

    ParallelOldGC
    可以使用-XX:+UseParallelOldGC开启,并且回收的线程数可以使用-XX:ParallelGCThreads来指定,同样如果cpu的核数小于8,线程数可以设置与核数一样,如果大于8,一般使用3+(cpu*5)/8

    区别
    ParallelGC在Full GC操作时会清空整个Heap中的垃圾对象,清除Perm区中已经被卸载的类信息,而ParallelOldGC是消除Heap中部分垃圾对象.

    优点:效率高
    缺点:当Heap区过大,应用程序暂停时间较长

  • CMS Collector
  • 可以使用-XX:+UseConcMarkSweepGC开启,并发线程数默认为4,当然它也可以使用ParallelCMSThreads来指定大小

    CMS GC是不同与Minor GC与Full GC,而是介于这两者之间,触发规则是检查Old区或者Perm区的使用率,当达到一定比例就会触发CMS GC,同时触发时会回收Old区中内存空间,这个值也可以使用-XX:CMSInitiatingOccupancyFraction指定,默认是92%.
    同样Perm区默认值也是92%,可通过-XX:CMSInitiatingPermOccupancyFraction指定,需要注意CMS GC只回收Old区与Perm区对象.
    优点:Old区回收暂停时间短
    缺点:产生内存碎片,整个GC耗时较长,比较耗cpu

发表评论(沙发空缺中,还不快抢~)

设置头像

*