- 引言
Java内存的管理包括内存的分配和回收,这两方面的工作都是由JVM来完成,这就使得java程序员可以不用关心内存的分配与回收,但是这也加重了JVM的负担。
关于内存管理有两方面的工作:分配与回收
下面开始内存回收的介绍:首先看几个问题,- JVM如何确定一个对象应该被回收?
- JVM是如何回收不再使用的java对象?
程序员通过New关键字创建一个对象,(即申请分配内存空间)由JVM来完成在堆中为每个对象分配空间、当一个java对象失去引用的时候,JVM垃圾回收机制会自动的清除他们,并回收它们所占用的内存空间。
回答第一个问题:
对于JVM垃圾回收机制来说,是否回收一个对象的标准在于:是否还有引用对象指向该对象。也就是说,只要有引用变量引用该对象,垃圾回收机制就不会回收它。实际上,对象被建立之后,垃圾回收机制就是实时的监控每个对象的运行状态。当发现某个对象不再被引用的时候,该对象就会在GC回收的时候被回收所占用的内存空间。
可以把JVM内存中对象的引用看成有向图,起点是引用变量,终点是java对象。在有向图中,main定点可达的对象都处于可达状态,GC并不会回收它;相反,GC就会回收相应内存的空间。
内存中运行的对象,根据其在有向图中的状态,可以分为下面三种:
1,可达状态:对象被创建后,有引用指向它
2,可恢复状态:程序中的某个对象不再有引用指向它,首先会进入此状态。此时GC准备回收它,在回收之前系统会调用finalise进行资源清理,一种结果是重写让一个或以上的变量指向它,那么次对象就会重新回到可达状态反之就会进入不可达状态;
3,不可达状态:只有在此状态下,系统才会真正的回收该对象。
可以看出引用在JVM的内存回收中有重要的作用,因此为了更好的管理对象的引用,JDK1.2以后提供了三个类,SoftReference、PhantomReference、WeakReference。分别代表了系统对对象的三种引用:软引用、虚引用、弱引用+强引用。
- 强引用:最常见的引用方式,程序创建一个对象,并把这个对象赋值给一个引用变量。被强引用的对象GC是绝对不会回收它的,所有这也是造成内存泄露的主要原因。
- 软引用:对于软引用对象而言,当系统内存足够的时候,它不会被系统回收,但是在内存空间不足的时候,GC就会回收该对象。
当程序需要大量创建某个类的新对象,而且有可能重新访问创建的老对象,可以充分的使用软引用来解决内存紧张的难题。 - 弱引用:与软引用相似,但是其生命周期更短。对于弱引用对象,不管系统 内存是否足够,只要GC运行,该类对象就会被回收。
- 虚引用:主要用于跟踪对象被垃圾回收的状态,它不能单独使用,必须与引用队列一起使用。
下面再来看Java的内存泄露:
1,什么是内存泄露?
程序运行的过程中,会不断的分配内存空间,那些不再被使用的内存空间应该被回收回来再次使用,如果这部分被分配的内存没有被回收回来,就会产生内存泄露。
2,为什么关注内存泄露?
内存不足不引起OutOfMemory,新的对象不能分配内存空间,程序中止。
3,内存泄露的主要原因?
对象任然被引用(状态可达),但是对象在应用程序中不会再被使用(成为垃圾),而根据前面讲述规则,此时GC并不会回收该对象(因为还处于可达状态),这就造成了内存泄露。
垃圾回收机制
主要任务:
1,实时的监控每个java对象,当某个对象处于不可达状态时候,回收所占用的内存。
2,清理内存分配、回收过程中产生的内存碎片。
垃圾回收的基本算法:
分代分别采取不同的算法进行。(关于代)
Young代:采用复制算法,只需要遍历那些处于可达状态的对象,因为绝大多数的对象不会被长时间的引用,因而导致这些对象大部分在其年轻代就被回收。
Old代:经理过年轻代的回收,还被保留的对象,GC就会将其由年轻代转化为此代。对于此代的对象而言,因为很少有对象会死掉,因而GC执行的频率较低,而每次执行GC都会比较耗时。
Permanent代:主要用于装载class、方法等信息,默认为64MB、GC通常不会回收此代的对象。
内存管理的技巧:
1,对于基本包装类,尽量使用直接量,而不是new开辟内存的方式。
2,程序中使用String连接字符串会生成许多的临时字符串,尽量使用StringBuffer或者StringBuilder来完成字符串的拼接。
3,尽早释放无用内存
4,由于静态变量声明周期交久,所有尽量少使用。
5,尽量少使用for循环创建某个对象。
6,对于经常使用的对象,使用缓存技术。OSCache,EHCache