在这里插入图片描述
Java 中的堆是 JVM 管理的最大的一块内存空间,主要用于存放Java类的实例对象,其被划分为两个不同的区域:新生代 ( Young )和老年代 ( Old ),其中新生代 ( Young ) 又被划分为:Eden、From Survivor和To Survivor三个区域,如下图所示:
从JDK8开始,Metaspace(元空间)替代了永久代,如下图所示:
无论哪个版本的JDK,其堆内存的划分都没有变化,下面详述Java堆中各个区域:
1、堆大小 = 新生代( Young ) + 老年代( Old ),其可以通过参数 –Xms、-Xmx 来指定:–Xms用于设置初始分配大小,默认为物理内存的1/16;-Xmx用于设置最大分配内存,默认为物理内存的1/4。默认情况下,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 ),即:新生代 ( Young ) = 1/3 的堆空间大小,老年代 ( Old ) = 2/3 的堆空间大小,因为这里面中的在S0和s1中只有会有一个会运行和另一个会在空闲的情况,则total的结果会在eden与from或to中一个值相加的和**,在下面到的演示中可以看到在s1与s0在进行的时候都是间隔进行的,也说明其中的so与s1的有一个是工作一个是空闲的**如下代码:
JDK8运行结果:
2、新生代 ( Young ) 被细分为 Eden 和 两个 Survivor 区域,为了便于区分,两个 Survivor 区域分别被命名为 from 和 to。默认情况下,Eden : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 ),即: Eden = 8/10 的新生代空间大小,from = to = 1/10 的新生代空间大小。JVM 每次只使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的,因此,新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间,在下面出现的图按是在jdk中的在点击工具下载GC插件。
3、工作原理:
a、Eden区为Java对象分配堆内存,当 Eden 区没有足够空间分配时,JVM发起一次Minor GC,将Eden区仍然存活的对象放入Survivor from区,并清空 Eden 区;
b、Eden区被清空后,继续为新的Java对象分配堆内存;
c、当Eden区再次没有足够空间分配时,JVM对Eden区和Survivor from区同时发起一次 Minor GC,把存活对象放入Survivor to区,同时清空Eden 区和Survivor from区;
d、Eden区继续为新的Java对象分配堆内存,并重复上述过程:Eden区没有足够空间分配时,把Eden区和某个Survivor区的存活对象放到另一个Survivor区;
e、JVM给每个对象设置了一个对象年龄(Age)计数器,每熬过一场Minor GC,对象年龄增加1岁,当它的年龄增加到阈值(默认为15,可以通过-XX:MaxTenuringThreshold 参数自定义该阀值),将被“晋升”到老年代,当 Old 区也被填满时,JVM发起一次 Major GC,对 Old 区进行垃圾回收。
**2,**在这里我们要先我们所创建的对象在jvm中是怎样的一个存储过程。
在jvm中包括年轻代和老年代;在年轻代中有:
在这里面始终都会保持着Eden区和一个幸存区中对象,没有被回收的对象放到另一个幸存中,当yong gc后则此时的Eden中和一个幸存者内是空的,一个幸存者内是有对象的,就是在两个幸存者中是来回存储的。
那为什么要用两个区域进行存储呢?
这里面的原地色为蓝色,在这里面有四个不同大小的对象,当要删除占用红色的对象的时候,又因为在我们所创建的对象中在jvm中分配的地址都是紧随的,而不是胡乱插序的,这里面的要是释放空间,以后的对象空间要往前移,这样效率会低,不往前移就会出现空间碎片。所以就出现了两个存储空间。
在我们的jvm内存分配的大小时我们是可以自己设置他们各自内存大小的。在我们输入jps的时候会出现有个无字号的数字就是我们的jvm的地址。
关于JVM的内存分配:
当一个对象没有引用的时候可能不会立即会回收,即使不会立即被回收,但它不能用了。