1.静态内存分配和回收
静态内存空间是在Java栈上分配的(编译时就确定的),当这个方法结束的时候,对应的栈帧也就取消,且静态内存空间也就回收了(针对栈帧而言)。
2.动态内存分配和回收
JAVA中对象的内存空间是动态分配的,所谓的动态分配就是在程序执行时才知道要分配的存储空间大小,而不是在编译时就能够确定的。
针对堆中对象什么时候不被使用,又如何来回收它们,这正是JVM的一个很重要的组件-----垃圾回收器要解决的问题。
垃圾检测的算法:
1.引用计数算法
2.可达性分析法
垃圾回收算法:
1.基于分代的垃圾回收算法
该算法设计思路:把对象按照寿命长短来分组,分为年轻代和年老代,新创建的对象分在年轻代,如果对象经过几次回收之后依然存活,那么再把这个对象划分到年老代。年老代的收集频率不像年轻代那么频繁,这样就减少了每次垃圾收集需要扫描的对象个数,从而提高了垃圾回收的效率。
这种思路是把堆划分成了若干个子堆,每个子堆都对应一个年龄代。
分别是: (1)新生代(Young区)其中Young区又分为Eden区和两个Survivor区。
(2)老年区(Old区)
(3)永久区(Perm区)
Young区又分为Eden区和两个survivor区,其中所有新创建的对象都在Eden区,当Eden区满了之后会触发minor GC将Eden区仍然存活的对象复制到其中一个Survivor区中,另外一个Survivor区中的存活对象也复制到这个Survivor中,以始终保证有一个Survivor区是空的。如果Survivor区也满了,GC收集器会将这些对象直接存放到Old区。如果在Survivor区中的对象足够老,也会被直接放到Old区。最终OLD区也满了的时候,就会出发Full GC,直接回收整个堆内存。
Perm区存放的是Class对象和ClassLoader。如果Perm区满了,同样触发Full GC。
SUN官方建议:Young区大小为整个堆大小的1/4
Young中的Survivor一般为整个堆大小的1/8
总结:当OLD区满了的时候和永久区满了的时候就会触发FULL GC.
2.标记-清除算法:
标记过程:引用计数法,可达性分析
CMS收集器就采用此算法,缺点是会产生大量的不连续的内存碎片,不利于后续装入大对象的操作。
3.复制算法:
把容量分成相同两个部分,每次使用其中一块,当其中一块用完了,复制对象到另一块上面去。现在的虚拟机大多使用这个方法来手机新生代中的对象,到survivor区中。
4.标记-整理算法
标记过程:引用计数和可达性分析
整理算法不是对可回收对象进行清理,而是把对象都向一端移动,然后直接清理掉端边界以外的内存。
4.Hotspot提供了6个垃圾收集器:
1.Serial 收集器(Client模式下默认):
是单线程的新生代垃圾收集器
新生代采用复制算法暂停所有用户线程。
老年代采用标记-整理算法暂停所有用户进程。
2. ParNew 收集器
是上面Serial收集器的多线程版本,在单CPU下表现不如Serical 收集器
3.Paralllel Scavenge 收集器
和ParNew类似,目的是达到可控制的吞吐量,可以指定吞吐量大小时间
4.Serical Old收集器
Serial Old是Serial收集器的在老年代的版本,同样是单线程
5. Parallel OLD 收集器
同样是Parlllel Scavenge收集器的老年代版本
6. CMS (Concurrent Mark Sweep)收集器
CMS收集器是一种获取最短回收停顿时间为目标的收集器。
基于 标记-清除 算法实现
Eden(新生代中的一部分):对象优先在Eden中分配,当Eden没有足够空间进行分配的时候,虚拟机将发起一次MinorGC.
老年代:大对象直接进入老年代,长期存活的对象将进入老年代。
Minor GC:一般当新对象生成,并且在Eden申请空间失败时,触发。将清除Eden区的非存活对象,并把存货对象移动到Survivor,然后整理两个Survivor区。该方式不会影响到老年代,此外,该GC推荐使用速度快,效率高的算法,使Eden区尽快空闲出来。
Full GC:对整个堆进行整理,包括Young、Tenured和Perm,因此为了提高系统性能,需要减少FullGC的次数。发生FullGC的场景有:年老代写满,持久代被写满和System.gc()被显示调用,上一次GC后Heap各域分配策略动态变化。