java从2.0版本开始引入了 强引用,软引用(SoftReference),弱引用(WeakReference),虚引用(PhantomReference)的概念。
他们被回收的优先级是依次递增的。
他们的生命周期是依次递减的。
以下是今天的学习目录
- 概念简介
- demo验证
- 总结
概念简介
强引用:有强引用指向的内存并且,只要从GC_root对象出发到该对象的引用有一个是可达的,那么就不会回收该块内存,否则就会回收。JVM就算抛出OOM异常也不会回收。
软引用:当只有软引用指向该对象,如果此时出现内存不足的情况时,GC就会回收这块只有弱引用指向的内存。
弱引用:当只有弱引用指向该对象,如果此时放生了gc操作,不管此时内存是否紧缺,该块内存都会被回收掉。
虚引用:这里引用网上看到的关于虚引用的解释 "虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃 圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
demo验证
强引用测试:每隔1s往集合中add 50000个对象,此时查看app的内存信息,发现直接抛出了OOM。该测试结果验证了 有强引用指向的内存并且,只要从GC_root对象出发到该对象的引用有一个是可达,就不会回收该对象,JVM就算抛出OOM异常也不会回收。
private void strongReferenceTest(){
final ArrayList<Object> list = new ArrayList<>();
new Thread(){
@Override
public void run() {
int count = 0;
while (true){
for(int i = 0; i < 500000; i++){
list.add(new TestObj());
}
count++;
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("===Test" ,"gc...");
System.gc();
float memory_total = Runtime.getRuntime().totalMemory() / 1024F / 1024F;
float memory_max = Runtime.getRuntime().maxMemory() / 1024F / 1024F;
float memory_free = Runtime.getRuntime().freeMemory() / 1024F / 1024F;
Log.e("===Test" , "List Size:" + list.size() + ", AddCount:" + count + ", memory_total:" + memory_total + ", max:" + memory_max + ", free:" + memory_free);
}
}
}.start();
}
log:
06-05 16:15:06.182 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:06.182 20935-21091/coml.android_lib E/===Test: List Size:500000, AddCount:1, memory_total:57.32199, max:384.0, free:4.7463074
06-05 16:15:08.046 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:08.046 20935-21091/coml.android_lib E/===Test: List Size:1000000, AddCount:2, memory_total:88.06508, max:384.0, free:5.400772
06-05 16:15:09.887 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:09.888 20935-21091/coml.android_lib E/===Test: List Size:1500000, AddCount:3, memory_total:120.102325, max:384.0, free:1.1645813
06-05 16:15:11.785 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:11.785 20935-21091/coml.android_lib E/===Test: List Size:2000000, AddCount:4, memory_total:151.4666, max:384.0, free:2.98172
06-05 16:15:13.715 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:13.715 20935-21091/coml.android_lib E/===Test: List Size:2500000, AddCount:5, memory_total:198.72322, max:384.0, free:6.768814
06-05 16:15:15.580 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:15.580 20935-21091/coml.android_lib E/===Test: List Size:3000000, AddCount:6, memory_total:221.84515, max:384.0, free:8.0
06-05 16:15:17.473 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:17.473 20935-21091/coml.android_lib E/===Test: List Size:3500000, AddCount:7, memory_total:271.77917, max:384.0, free:8.0
06-05 16:15:19.364 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:19.365 20935-21091/coml.android_lib E/===Test: List Size:4000000, AddCount:8, memory_total:289.34973, max:384.0, free:8.0
06-05 16:15:21.273 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:21.273 20935-21091/coml.android_lib E/===Test: List Size:4500000, AddCount:9, memory_total:319.8697, max:384.0, free:8.0
06-05 16:15:23.235 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:23.236 20935-21091/coml.android_lib E/===Test: List Size:5000000, AddCount:10, memory_total:350.3812, max:384.0, free:7.999359
06-05 16:15:26.189 20935-21091/coml.android_lib E/===Test: gc...
06-05 16:15:26.189 20935-21091/coml.android_lib E/===Test: List Size:5500000, AddCount:11, memory_total:382.60443, max:384.0, free:0.0
06-05 16:15:57.297 20935-20944/coml.android_lib E/System: Uncaught exception thrown by finalizer
06-05 16:16:08.864 20935-20944/coml.android_lib E/System: java.lang.OutOfMemoryError: OutOfMemoryError thrown while trying to throw OutOfMemoryError; no stack trace available
软引用测试:
case 1:每隔1s向list中添加20000条数据(为的就是测试在heap内存不足进行扩容时,查看 只有软引用指向的对象的内存是否会被回收)。此时发现,当heap当前剩余的内存不能满足对象申请占用的内存并进行扩容时,只有软引用指向的对象内存会被回收。
private void softReferenceTest_Case_1(){
final ArrayList<TestObj> list = new ArrayList<>();
final SoftReference<TestObj> softReference = new SoftReference<TestObj>(new TestObj());
new Thread(){
@Override
public void run() {
while (true){
for(int i = 0; i < 20000; i++){
list.add(new TestObj());
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("===Test" ,"gc...");
System.gc();
float memory_total = Runtime.getRuntime().totalMemory() / 1024F / 1024F;
float memory_max = Runtime.getRuntime().maxMemory() / 1024F/1024F;
float memory_free = Runtime.getRuntime().freeMemory() / 1024F/1024F;
Log.e("===Test" ,"meomory:" + "total:" + memory_total + ", max:" + memory_max + ", free:" + memory_free);
Log.e("===Test" ,"weakReference is null:" + (softReference.get() == null));
}
}
}.start();
}
log
06-05 16:24:11.558 23235-23312/coml.android_lib E/===Test: gc...
06-05 16:24:11.558 23235-23312/coml.android_lib E/===Test: meomory:total:25.739548, max:384.0, free:6.355728
06-05 16:24:11.558 23235-23312/coml.android_lib E/===Test: weakReference is null:false
06-05 16:24:12.622 23235-23312/coml.android_lib E/===Test: gc...
06-05 16:24:12.623 23235-23312/coml.android_lib E/===Test: meomory:total:25.739548, max:384.0, free:4.7508545
06-05 16:24:12.623 23235-23312/coml.android_lib E/===Test: weakReference is null:false
06-05 16:24:13.701 23235-23312/coml.android_lib E/===Test: gc...
06-05 16:24:13.701 23235-23312/coml.android_lib E/===Test: meomory:total:25.739548, max:384.0, free:3.1917572
06-05 16:24:13.702 23235-23312/coml.android_lib E/===Test: weakReference is null:false
06-05 16:24:14.782 23235-23312/coml.android_lib E/===Test: gc...
06-05 16:24:14.782 23235-23312/coml.android_lib E/===Test: meomory:total:25.739548, max:384.0, free:1.9725037
06-05 16:24:14.782 23235-23312/coml.android_lib E/===Test: weakReference is null:false
06-05 16:24:15.863 23235-23312/coml.android_lib E/===Test: gc...
06-05 16:24:15.864 23235-23312/coml.android_lib E/===Test: meomory:total:25.739548, max:384.0, free:0.24163818
06-05 16:24:15.864 23235-23312/coml.android_lib E/===Test: weakReference is null:false
06-05 16:24:16.084 23235-23245/coml.android_lib E/===Test: finalize()...
06-05 16:24:16.939 23235-23312/coml.android_lib E/===Test: gc...
06-05 16:24:16.939 23235-23312/coml.android_lib E/===Test: meomory:total:33.614517, max:384.0, free:7.998123
06-05 16:24:16.939 23235-23312/coml.android_lib E/===Test: weakReference is null:true
06-05 16:24:18.002 23235-23312/coml.android_lib E/===Test: gc...
06-05 16:24:18.003 23235-23312/coml.android_lib E/===Test: meomory:total:33.614517, max:384.0, free:6.0112762
06-05 16:24:18.003 23235-23312/coml.android_lib E/===Test: weakReference is null:true
06-05 16:24:19.065 23235-23312/coml.android_lib E/===Test: gc...
06-05 16:24:19.066 23235-23312/coml.android_lib E/===Test: meomory:total:33.614517, max:384.0, free:4.7850494
06-05 16:24:19.066 23235-23312/coml.android_lib E/===Test: weakReference is null:true
case 2:对case1的代码稍加修改,除了用软引用指向某对象,再用强引用指向该对象,查看该对象在发生内存不足时是否会被回收。查看log发现,直到jvm都抛出OOM异常之前,软引用指向的对象依然没有被回收,这充分证明了 “只要是强引用指向的对象并且从GC_root出发是可达的,那么gc就不会回收该对象占用的内存,哪怕会导致OOM异常的产生”。
private void softReferenceTest_Case_2(){
final ArrayList<TestObj> list = new ArrayList<>();
final TestObj testObj = new TestObj(); //声明一个 强引用指向 testObj
final SoftReference<TestObj> softReference = new SoftReference<TestObj>(testObj); //声明一个弱引用指向 testObj
new Thread(){
@Override
public void run() {
while (true){
for(int i = 0; i < 200000; i++){
list.add(new TestObj());
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
float memory_total = Runtime.getRuntime().totalMemory() / 1024F / 1024F;
float memory_max = Runtime.getRuntime().maxMemory() / 1024F / 1024F;
float memory_free = Runtime.getRuntime().freeMemory() / 1024F / 1024F;
Log.e("===Test" ,"meomory:" + "total:" + memory_total + ", max:" + memory_max + ", free:" + memory_free);
Log.e("===Test" ,"TestObj is null:" + (testObj == null));
Log.e("===Test" ,"weakReference is null:" + (softReference.get() == null));
}
}
}.start();
}
log
06-05 17:16:26.811 6322-6428/coml.android_lib E/===Test: meomory:total:58.858932, max:384.0, free:7.996063
06-05 17:16:26.811 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:26.811 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:16:28.663 6322-6428/coml.android_lib E/===Test: meomory:total:89.25787, max:384.0, free:4.0321503
06-05 17:16:28.663 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:28.663 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:16:30.496 6322-6428/coml.android_lib E/===Test: meomory:total:123.08865, max:384.0, free:7.9961243
06-05 17:16:30.496 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:30.496 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:16:32.413 6322-6428/coml.android_lib E/===Test: meomory:total:156.49597, max:384.0, free:8.0
06-05 17:16:32.414 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:32.414 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:16:34.278 6322-6428/coml.android_lib E/===Test: meomory:total:199.95728, max:384.0, free:8.0
06-05 17:16:34.278 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:34.278 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:16:36.137 6322-6428/coml.android_lib E/===Test: meomory:total:221.84827, max:384.0, free:8.0
06-05 17:16:36.137 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:36.137 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:16:37.961 6322-6428/coml.android_lib E/===Test: meomory:total:271.7821, max:384.0, free:8.0
06-05 17:16:37.961 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:37.961 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:16:39.848 6322-6428/coml.android_lib E/===Test: meomory:total:289.35284, max:384.0, free:8.0
06-05 17:16:39.848 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:39.848 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:16:41.805 6322-6428/coml.android_lib E/===Test: meomory:total:319.87274, max:384.0, free:8.0
06-05 17:16:41.805 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:41.806 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:16:43.699 6322-6428/coml.android_lib E/===Test: meomory:total:350.39243, max:384.0, free:8.0
06-05 17:16:43.699 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:43.700 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:16:47.119 6322-6428/coml.android_lib E/===Test: meomory:total:382.62027, max:384.0, free:0.0
06-05 17:16:47.119 6322-6428/coml.android_lib E/===Test: TestObj is null:false
06-05 17:16:47.119 6322-6428/coml.android_lib E/===Test: weakReference is null:false
06-05 17:17:21.464 6322-6340/coml.android_lib E/System: Uncaught exception thrown by finalizer
06-05 17:17:26.141 6322-6340/coml.android_lib E/System: java.lang.OutOfMemoryError: Failed to allocate a 36 byte allocation with 32 free bytes and 32B until OOM
弱引用测试:当代码跑起来后,我们用AS提供的Android-Profiler切换至Momery卡片,点击“Force garbage collection”按钮处发“强制gc操作”。此时查看log发现,只有软引用指向的对象在强制执行gc操作后马上就被回收了(这里之所以不用System.gc()处发gc操作,是因为此方法只是通知jvm现在执行gc操作,但是不保证一定会执行)。此操作验证了 “当发生gc操作时,不管当前内存是否够用,都会回收弱引用指向的对象内存”。
private void weakReferenceTest(){
final ArrayList<Object> list = new ArrayList<>();
final Object strongReference = new Object();
final WeakReference<Object> weakReference = new WeakReference<Object>(new Object());
new Thread(){
@Override
public void run() {
while (true){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
float memory_total = Runtime.getRuntime().totalMemory() / 1024F / 1024F;
float memory_max = Runtime.getRuntime().maxMemory() / 1024F / 1024F;
float memory_free = Runtime.getRuntime().freeMemory() / 1024F / 1024F;
Log.e("===Test" ,"meomory:" + "total:" + memory_total + ", max:" + memory_max + ", free:" + memory_free);
Log.e("===Test" ,"strongReference is null:" + (strongReference == null));
Log.e("===Test" ,"weakReference is null:" + (weakReference.get() == null));
}
}
}.start();
}
log
06-05 17:29:23.019 10398-10522/coml.android_lib E/===Test: meomory:total:25.644852, max:384.0, free:7.625351
06-05 17:29:23.019 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:23.019 10398-10522/coml.android_lib E/===Test: weakReference is null:false
06-05 17:29:24.020 10398-10522/coml.android_lib E/===Test: meomory:total:25.644852, max:384.0, free:7.6084137
06-05 17:29:24.020 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:24.020 10398-10522/coml.android_lib E/===Test: weakReference is null:false
06-05 17:29:25.020 10398-10522/coml.android_lib E/===Test: meomory:total:25.786163, max:384.0, free:7.9948425
06-05 17:29:25.020 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:25.020 10398-10522/coml.android_lib E/===Test: weakReference is null:true
06-05 17:29:26.021 10398-10522/coml.android_lib E/===Test: meomory:total:25.786163, max:384.0, free:7.978073
06-05 17:29:26.021 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:26.021 10398-10522/coml.android_lib E/===Test: weakReference is null:true
06-05 17:29:27.021 10398-10522/coml.android_lib E/===Test: meomory:total:25.786163, max:384.0, free:7.977936
06-05 17:29:27.021 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:27.021 10398-10522/coml.android_lib E/===Test: weakReference is null:true
06-05 17:29:28.022 10398-10522/coml.android_lib E/===Test: meomory:total:25.786163, max:384.0, free:7.9777985
06-05 17:29:28.022 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:28.022 10398-10522/coml.android_lib E/===Test: weakReference is null:true
06-05 17:29:29.023 10398-10522/coml.android_lib E/===Test: meomory:total:25.786163, max:384.0, free:7.977661
06-05 17:29:29.023 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:29.023 10398-10522/coml.android_lib E/===Test: weakReference is null:true
06-05 17:29:30.023 10398-10522/coml.android_lib E/===Test: meomory:total:25.786163, max:384.0, free:7.977524
06-05 17:29:30.023 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:30.023 10398-10522/coml.android_lib E/===Test: weakReference is null:true
06-05 17:29:31.024 10398-10522/coml.android_lib E/===Test: meomory:total:25.786163, max:384.0, free:7.9773865
06-05 17:29:31.024 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:31.024 10398-10522/coml.android_lib E/===Test: weakReference is null:true
06-05 17:29:32.025 10398-10522/coml.android_lib E/===Test: meomory:total:25.786163, max:384.0, free:7.977249
06-05 17:29:32.025 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:32.025 10398-10522/coml.android_lib E/===Test: weakReference is null:true
06-05 17:29:33.025 10398-10522/coml.android_lib E/===Test: meomory:total:25.786163, max:384.0, free:7.977112
06-05 17:29:33.025 10398-10522/coml.android_lib E/===Test: strongReference is null:false
06-05 17:29:33.026 10398-10522/coml.android_lib E/===Test: weakReference is null:true
虚引用待更新。。。。。。。
总结
- 如果某一个对象,存在强引用指向它,那么该对象就不会被gc当成垃圾回收掉。
- 如果某一个对象,只存在软引用指向它,只有再内存不足时才会被gc回收掉。
- 如果某一个对象,只存在弱引用指向它,当jvm发生gc操作时,此时不论内存是否足够,都会回收该对象。
参考链接:https://blog.csdn.net/haixia_12/article/details/51888707
网友评论