很高兴能写下这篇博客,因为这是对我学习新知识的总结,更重要的是可以同大家一起分享知识,畅游在知识的海洋。
欢迎留言,我会定时查阅留言,及时答复并改正博客的不足,请多包容,谢谢!你们也要多注意身体健康!
再苦再累,我不会放弃,因为夜空中最亮的星是我的梦。
谈到强引用(StrongReference)、软引用(SoftReference),弱引用(WeakReference)、虚引用(PhantomReference),会涉及到垃圾回收器机制GC。
什么是GC(全称:GabageCollection)?
GC通常是运行在一个独立的、优先级比较低的线程中,实时监测并释放“无效”的内存。
什么是“无效"的内存单元?
一般GC采用引用计数法来判断一个内存单元(一个变量)是否是无效的内存。
引用计数法(引用计数法只是GC中一种常用的方法,还会用到年代方法等)是指一个变量或一块内存当前被引用的次数,如果引用次数为0,则表示这个变量或这块内存未被引用,因此GC“有可能”去释放它 ,为什么说有可能?首先GC运行在一个独立的、优先级比较低的线程中,其次GC回收的具体工作也是比较复杂的,比如说需要释放大量内存的时候,而CPU资源又相对紧张,GC可能会选择性 的释放一些内存资源,具体回收方法取决于GC内部的算法。
一个占用内存较大的对象、或者一个存储图片的对象,他们有时无用、又占用大量内存资源而GC又没有办法去释放,从而造成严重后果。一般原则是:对占用大量内存的变量使用完后主动将其置为NULL,可能的话主动调用一次GC回收机制:System.gc(), 特别是一些static型的引用风险很大。
/**
*大概译文:调用System.gc()方法时,会指示虚拟机去运行垃圾回收器,但这仅是一个提示作用,不会保证虚拟机实际运行
* Indicates to the VM that it would be a good time to run the
* garbage collector. Note that this is a hint only. There is no guarantee
* that the garbage collector will actually be run.
*/
public static void gc() {
boolean shouldRunGC;
synchronized(lock) {
shouldRunGC = justRanFinalization;
if (shouldRunGC) {
justRanFinalization = false;
} else {
runGC = true;
}
}
if (shouldRunGC) {
Runtime.getRuntime().gc();
}
}
1.强引用 StrongReference
强引用是使用最普遍的引用,如果一个对象具有强引用,垃圾回收器不会回收它。只有当其他对象没有对这个对象强引用时,才可能被GC回收掉。否则当内存空间不足
,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会回收强引用的对象。
/**
* 测试强引用
*/
public void testStrongReference(){
System.out.println("\n***************强引用********************\n");
String strongStr = new String("强引用"); //强引用,永远不会被gc回收,即使程序因OutOfMemory而崩溃
strongStr = null; //取消强引用,内存不足时,有可能被gc回收,因为gc处在的线程中优先级比较低
System.gc();
}
2.软引用 SoftReference:
如果一个对象具有软引用,当内存空间足够,垃圾回收器就不会回收它,当内存空间不足了,就可能回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以
被程序使用,软引用可用来实现内存敏感的高速缓存。一般对于这种占用内存资源比较大的,又不是必要的变量,或者一些占用大量内存资源的一些缓存的变量,就需要考虑
用SoftReference。
/**
* 测试软引用
*/
public void testSoftReference(){
System.out.println("\n***************软引用********************\n");
String softStr = new String("软引用");
ReferenceQueue softQueue = new ReferenceQueue();
//如果gc预回收软引用,在回收前将该引用对象加入到ReferenceQueue中
SoftReference<String> softRef = new SoftReference<String>(softStr,softQueue);
softStr = null; //取消强引用
System.out.println("软引用...gc回收前...str = "+softRef.get());
System.gc();
if(softRef.get() == null){
System.out.println("软引用...利用SoftReference判断...内存不足...gc已回收软引用...str = "+softRef.get());
}else{
System.out.println("软引用...利用SoftReference判断...内存充足...gc未回收软引用...");
}
Reference softPollRef = (Reference)softQueue.poll();
if(softPollRef != null){
System.out.println("软引用...利用ReferenceQueue判断...内存不足...gc已回收软引用...str = "+softPollRef.get());
}else{
System.out.println("软引用...利用ReferenceQueue判断...内存充足...gc未回收软引用...");
}
/**
* 内存充足结果:
软引用...gc回收前...str = 软引用
软引用...利用SoftReference判断...内存充足...gc未回收软引用...
软引用...利用ReferenceQueue判断...内存充足...gc未回收软引用...
*/
}
3. 弱引用 WeakReference
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。如果一个对象只具有弱引用,只要垃圾回收器在内存空间检测到了,不管当前内存空间足够
与否,都会回收对应的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
/**
* 测试弱引用
*/
public void testWeakReference(){
System.out.println("\n***************弱引用********************\n");
// String weakStr = null; //弱引用,空值不会被加入到ReferenceQueue中
String weakStr = new String("弱引用"); //强引用创建新的string类型数据
//只有该引用对象被gc回收后,才会添加到(但不是一定)ReferenceQueue中,但被gc回收后,有时queue.poll中又没有数据
ReferenceQueue weakQueue = new ReferenceQueue();
WeakReference<String> weakReference = new WeakReference<String>(weakStr,weakQueue);
weakStr = null; //取消强引用,gc才会回收弱引用对象
System.out.println("弱引用...利用WeakReference判断...gc回收前...weakStr = "+weakReference.get());
System.gc();
System.out.println("弱引用...利用WeakReference判断...gc回收后...weakStr = "+weakReference.get());
/**
*
* 原文:(地址:Java? Platform Standard Ed. 6----http://docs.oracle.com/javase/6/docs/api/)
* Polls this queue to see if a reference object is available.
* If one is available without further delay then it is removed
* from the queue and returned. Otherwise this method immediately returns null.
*
* 译文:
* 轮询此队列,查看引用对象是否可获得的。
* 如果一个引用对象是可获得的,并且没有进一步的延迟,
* 然后它会被从队列中移除和返回。
* 如果该引用对象发生延迟,这个方法立即返回null
*
*结论:
*通过译文可以看到,如果对列中可获得的引用没有进一步延迟,该引用对象会被立即返回,
*如果有延迟发生,这个方法立即返回null。所以reference有时等于null,有时不为null,
*所以也就会出现以下注释的两种结果(结果1,结果2)
*
*要出现以下语意的结果,前提必须调用System.gc(),且该引用对象已取消强引用
*/
Reference weakPollRef = (Reference)weakQueue.poll();
if(weakPollRef != null){
System.out.println("弱引用...利用ReferenceQueue判断...gc已回收弱引用...queue中的值 = "+weakPollRef.get());
}else{
System.out.println("弱引用...利用ReferenceQueue判断...gc已回收弱引用......获得对列中的引用对象发生延迟...");
}
/*
结果1:
弱引用...利用WeakReference判断...gc回收前...weakStr = 弱引用
弱引用...利用WeakReference判断...gc回收后...weakStr = null
弱引用...利用ReferenceQueue判断...gc已回收弱引用......获得对列中的引用对象发生延迟...
结果2:
弱引用...利用WeakReference判断...gc回收前...weakStr = 弱引用
弱引用...利用WeakReference判断...gc回收后...weakStr = null
弱引用...利用ReferenceQueue判断...gc已回收弱引用...queue中的值 = null
*/
}
4.虚引用 PhantomReference
如果一个对象只具有虚引用,那么它就和没有任何引用一样,随时会被jvm当作垃圾进行回收,虚引用主要是用于跟踪一个对象何时被GC回收。
/**
* 测试虚引用
*/
public void testPhantomReference(){
System.out.println("\n***************虚引用********************\n");
String phantomStr = new String("虚引用测试");
ReferenceQueue phantomQueue = new ReferenceQueue();
PhantomReference<String> phantomReference = new PhantomReference<String>(phantomStr, phantomQueue);
phantomStr = null; //取消强引用
/**
* 有关phantomReference.get()的说明:
*
* 原文:
* Returns {@code null}. The referent of a phantom reference is not
* accessible.
*
* 译文:
* phantomReference.get()返回空值,虚引用的引用对象是不可获得的
*
* 结论:
*与译文可知,phantomReference.get()方法始终返回空值
*/
System.out.println("虚引用....利用PhantomReference...gc回收前...phantomStr = "+phantomReference.get());
System.gc();
System.out.println("虚引用....利用PhantomReference...gc回收后...phantomStr = "+phantomReference.get());
/**
* 同软引用一样,会出现两种结果,请详细查看软引用说明
* 要出现以下语意的结果,前提必须调用System.gc(),且该引用对象已取消强引用
*/
Reference phantomPollRef = phantomQueue.poll();
if(phantomPollRef != null){
System.out.println("虚引用....利用ReferenceQueue...gc已回收...phantomStr = "+phantomPollRef.get());
}else{
System.out.println("虚引用....利用ReferenceQueue...gc已回收虚引用......获得对列中的引用对象发生延迟......");
}
/**
* 结果1:
虚引用....利用PhantomReference...gc回收前...phantomStr = null
虚引用....利用PhantomReference...gc回收后...phantomStr = null
虚引用....利用ReferenceQueue...gc已回收...phantomStr = null
*结果2:
虚引用....利用PhantomReference...gc回收前...phantomStr = null
虚引用....利用PhantomReference...gc回收后...phantomStr = null
虚引用....利用ReferenceQueue...gc已回收虚引用......获得对列中的引用对象发生延迟......
*/
}