JVM之堆空间探秘

一、什么是堆?

堆是所有线程共享的主要用来存储对象。其中,堆可分为:新生代和老年代两块区域。使用NewRatio参数来设定比例。对于新生代,一个Eden区和两个Suvivor区,使用参数SuvivorRatio来设定大小

新生代

  • 伊甸园区
    所有的对象都是在伊甸园区new出来的
  • 幸存0区&幸存1区
    伊甸园区中对象满了后会出发垃圾回收,轻GC从而有一部分被清理到了幸存区中,0区和1区会相互交换,互为from和to

老年代

  • 幸存区也满了后,会触发重GC,清理一部分到老年代中,据统计,99%的都活不到老年代
  • 如果老年代也满了,就会报错 Out Of Memory(OOM) — 内存溢出

二、永久代\元空间和方法区

方法区
也称非堆(Non-Heap),是一个被线程共享的内存区域。其中主要存储加载的类字节码、class/method/field等元数据对象、static-final常量、static变量、jit编译器编译后的代码等数据。另外,方法区包含了一个特殊的区域“运行时常量池”,里面有字符串常量等

永久代/元空间

  • 这两者都是用于实现方法区的,jdk1.6之前,常量池被放在了方法区中,jdk1.7时,常量池放在了堆中,jdk1.8之后,取消了永久代,常量池被放进了元空间中
  • 这个区域是常驻内存的,用来存放JDK自身携带的Class对象,interface元数据,java运行时的一些环境等等,这个区域的垃圾难以回收,关闭JVM虚拟机就会释放这个区域的内存
  • 什么时候会满呢?例如一个启动类加载了大量的第三方jar包,Tomcat部署了太多应用,大量动态生成的反射类等

三、图示

JVM之堆空间探秘