一.内存管理
Java的内存管理很大程度是指对,堆中对象的管理,因为栈中的内存在调用方法结束后就会自动释放.
对象的内存分配一般都使用new关键字来进行创建对象,并分配内存
对象的内存释放,直接赋值null即可,Java的垃圾回收器会将所有无法到达的对象清理释放内存
二.垃圾回收过程
1.发现无用的对象
2.回收无用对象所占用的内存
三.垃圾回收算法
1.引用计数法
即堆中每一个对象都会对应着一个引用计数器,当有引用指向它时,它的引用计数器就会加一,此方法看似很好,但是引来一个问题,如果栈中方法结束,引用被抹除,会不会还有引用指向它,是有这种可能的,我们如果让对象中有一块区域是指向另一个对象,另一个对象同样如此,出现互相引用或者循环引用,那么他们的引用计数器就会是1,就不会被释放,但是需要使用他们的方法都已经结束,不再需要他们,这就会造成浪费,这种情况大量出现的话,久而久之,堆中的内存就会被占满.
如图当1和2的指向消失时,3和4的指向未消失,该内存就得不到释放
代码如下
public class Test1 {
public static void main(String[] args) {
A duiXiang1 = new A();
B duixiang2 = new B();
duiXiang1.b = duixiang2;
duixiang2.b = duiXiang1;
duixiang1 = null;
duixiang2 = null;
}
}
class A{
int a;
B b;
}
class B{
int a;
A b;
}
2.引用可达法
我们可以把所有的引用关系看作一张图,从根节点开始,往下找对应的节点,不断的找,凡是没有遍历到的,即是无用的垃圾,会被回收掉.
一旦1和2断掉,无法从根节点找到对象就会被回收
四.分代垃圾回收机制
由于不同对象的生命周期不同,可以对不同的对象采取不一样的回收算法,时回收效率达到最大化,我们可以将对象分为年轻代, 年老代, 和持久代,我们将不同的对象放到堆中不同的区域.JVM将其划分为Eden,Survivor和Old区域.
- 年轻代包括Eden 和 Survivor区域.所有新生成的对象都会被放在Eden区域.在此区域中的生命周期短的对象会被及时的处理掉,而处理他们的是Miner Gc,它会频繁的清理年轻代中的内存.在Eden区域,当对象不断被放进来,此区域满了之后,Minor Gc就会进行垃圾回收,将未被回收仍在使用的这些对象放到Survivor1区,此时的Eden区域就被清空了,同理当Survivor1区满了之后,Miner Gc也会开始进行垃圾回收,将此区域清空,未被回收仍在利用的放进Survivor2区.然后当Survivor2区满了,又会将剩下的放入Survivor1区,在Survivor1和2区进行来回的颠倒.在年轻代里,当一个对象经历了(默认)15次的垃圾回收,仍旧存在使用,就会被放到年老代区域.
- 年老代中存放的是一些生命周期比较长的对象,当年老代的对象越来越多的时候,就会启动Magor Gc 和Full Gc对年轻代和年老代进行全面清理
- 永久代,用于存放静态文件,如Java类的信息,方法.永久代对垃圾回收并没有显著的影响,因为静态文件从程序启动调用后会被一直放在那里,JDK8以后,使用metaspace元数据空间和堆代替,元数据空间在本地内存上.
MinorGc:
用于清理年轻代区域,在Eden区域满了之后,会触发MinorGc,清理无用的对象,将有用的对象复制到Survivor1和Survivor2区中,当这两个区域满了之后,MinorGc同样如此.
MajorGc
用于清理年老代区域
Full Gc
用于清理年轻代,年老代区域,成本较高,会对系统性能产生影响.而对JVM的调优很大一部分是对Full Gc的调优,我们可以通过System.gc(),来向JVM申请使用Full Gc,但要少使用,因为成本高,影响系统性能.
如图所示