二: Jvm内存模型

为每个对象生命周期不一样,jvm在做内存管理的时候,就帮我们分成了三个区域:

  1.  新生代(回收频率高)   新生和老年默认大小比例为1:2

  2.  老年代(回收频率低)     最好所有的对象都不要进入老年代,最好新生代能及时回收空对象释放空间供下次使用。

  3.  永久代(一般放类的加载信息,常量,静态变量)。

 

GC回收算法:

  GC回收是采用的复制回收算法,默认将新生代内存分为8:1:1,达到90%的利用率。

    创建的对象默认放在eden区中,eden区内存快满的时候,就会触发minor gc来回收空对象,将不能回收的对象放到s0区里面;

    当再次创建多个对象后   eden区又快满了,这时又触发minor gc回收eden和s0里面的空对象,若esdn区和s0区内存不足,将剩余的放到s1区中;

    如此反复新生代没有空间时,对象就会放到老年代中。


  从上图可以看出jdk1.8之前:新生代,老年代放在heap中, 永久代放在方法区中;

  在jdk1.8的时候,就将永久代放到了一块叫Meta Space(元空间)的本地内存中。

    官方之所以这么设计,是为了解决永久代会溢出的问题,meta space有点像ArrayList,拥有自动扩容的特性,从而防止溢出。当然它也不是越大越好,太大了会因为内存占用过多,从而使得堆外内存空间狭小而容易出现内存溢出的情况。这些都是可配置的。

  

指针碰撞:

  如下图,第一次创建对象的时候线程开辟了一个空间,第二次创建对象线程所有开了了一个空间,如果多个线程同时创建就会出现“抢占”空间的情况出现指针碰撞,jvm就通过CAS来控制先来

    后到的顺利,理解成线程锁一样。但是这样创建对象还是CAS还是会出现竞争激烈的情况从而消耗CPU影响性能。为了解决这个问题,jvm又提供了栈上分配。内存规整(即内存连续有规律)

    

栈上分配:

  栈上分配的本质还是在堆中分配内存。

  如下图:在堆里面,每个线程都有自己的Thread local Alltion Buffer,他们都是在自己的空间里面创建对象,这样就不会出现抢占的情况了,从而提高了性能。

对象分配规则:

  (1)对象优先分配在Eden区,如果Eden内存不够,虚拟机就执行一次Minor GC

  (2)大对象(大对象指需要大量连续内存空间的对象)直接进入老年代.这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。

  (3)长期存活的对象进入老年代.虚拟机为每个对象都定义一个年龄计数器,如果对象经过一次Minor GC就去Survivor区,之后每经过一次Minor GC,年龄就会加一,直到15之后就去老年代.

  (4)动态判断对象的年龄.如果Survivor区相同年龄的对象的总和大于Survivor的一半,那么大于或者等于这个年龄的对象直接去老年代

猜你喜欢

转载自www.cnblogs.com/wlwl/p/9463735.html