一、垃圾收集器:GC.Garbage Collection
解决的问题:如何回收分配给对象的内存。①哪些内存需要回收?②什么时候回收?③如何回收?
①java堆和方法区 的内存是不确定的,动态的,需要关注这2部分。
判断对象是否已死?进行标记
1.引用计数:给对象设置一个计数器.当被引用一次就就+ 1,引用失效就-1。当计数器为0.就回收了。
特点:简单,效率高。但是无法解决相互循环引用的情况,比如a.instance=b;b.instance=a。则a,b对象永远无法被回收。
2.可达性分析算法:用阿里判断对象是否存活。从“”GC Roots“”对象开始,向下面节点进行搜索,走过的路径成为引用链。当通过该路径无法到达一个对象时,该对象被标记回收。
可作为gc roots的对象:
虚拟机栈(本地方法表)中引用的对象(因为在栈内,被线程引用),方法区中类静态属性引用的对象,方法区中常量引用的(常量存放在常量池中,常量池是方法区的一部分)对象,native方法引用的对象
说明:这来方法只用于标记,并不执行回收操作。
GC的4中收集方法:
1.标记清除:思想最基础。先标记,然后清除。 缺点:效率低下;没有对清除后产生的碎片进行整理。
2.复制算法:将内存分为大小相等2块。每次只使用一块,当这块用完了,就将这块中存在的对象复制到另外一块,本块清理干净。 缺点;内存缩小为原来一半。
3.标记-整理:将存在对象整理到一端,清除掉剩下的全部。
4.分代收集:java对象分新生代,老年代。根据对象存活特点,灵活采用不同方法。
GC收集器的分类?分类指标
分类指标:新,老年代划分 单、多线程划分。
单线程的serial、-》改进版本ParNew多线程 这是最早的
CMS:目标是 获取最小回收停顿时间 给用户最好的体验。
G1收集器:最先进的。它可以支持新,老,单,多。广泛使用。
三、年轻代,年老代,永久代。FullGC,MinorGC
tspot VM提供的垃圾回收器是一个分代垃圾回收器(Generational GC)[9,16,18]-将内存划分为不同的阶段,也就是说,不同的生命周期的对象放置在不同的地址池中。这样的设计是基于弱年代假设(Weak Generational Hypothesis):
1.越早分配的对象越容易失效;
2.老对象很少会引用新对象。
这种分代方式可以减少垃圾回收的停顿时间以及大范围对象的回收成本。Hotspot VM将其堆空间分为三个分代空间:
1. 年轻代(Young Generation)
○ Java应用在分配Java对象时,这些对象会被分配到年轻代堆空间中去
○ 这个空间大多是小对象并且会被频繁回收
○ 由于年轻代堆空间的垃圾回收会很频繁,因此其垃圾回收算法会更加重视回收效率
2. 年老代(Old Generationn)
○ 年轻代堆空间的长期存活对象会转移到(也许是永久性转移)年老代堆空间
○ 这个堆空间通常比年轻代的堆空间大,并且其空间增长速度较缓
○ 由于大部分JVM堆空间都分配给了年老代,因此其垃圾回收算法需要更节省空间,此算法需要能够处理低垃圾密度的堆空间
3. 持久代(Permanent Generation)
○ 存放VM和Java类的元数据(metadata),以及interned字符串和类的静态变量
次收集(Minor GC)和全收集(Full GC)
当这三个分代的堆空间比较紧张或者没有足够的空间来为新到的请求分配的时候,垃圾回收机制就会起作用。有两种类型的垃圾回收方式:次收集和全收集。当年轻代堆空间满了的时候,会触发次收集将还存活的对象移到年老代堆空间。当年老代堆空间满了的时候,会触发一个覆盖全范围的对象堆的全收集。
次收集
- 当年轻代堆空间紧张时会被触发
- 相对于全收集而言,收集间隔较短
全收集
- 当老年代或者持久代堆空间满了,会触发全收集操作
- 可以使用System.gc()方法来显式的启动全收集
- 全收集一般根据堆大小的不同,需要的时间不尽相同,但一般会比较长。不过,如果全收集时间超过3到5秒钟,那就太长了[1]
二、内存分配策略
①对象优先在新生代Eden区分配。
②大对象直接进入老年代。需要连续内存空间的对象。比如一个大数组。
③长期存活的对象进入老年代。