引用类型
之前关于这个,看了一些文章,但是总是觉得讲的不够清晰,自己都实践了很多次,才反映出来,其中暴漏出了自己很多不足,GC命令不熟悉,导致我测试了很久一直不触发,软引用的GC。本来代码里面留了很多不同的类型,不过感觉看起来还是太麻烦了,直接删除了
额外提示几句,static是方法区分配内存的。
设置JVM堆大小不要设置大了,我这里是12M,64位机器上应该都没问题,32位我没测试
用自己的话描述一下
强引用:非缓存,无法GC(指的是,生存周期之内,function没结束,结束了肯定缓存,我这里是main函数走到底)
软引用:缓存
弱引用:最差的缓存
虚引用:异步判断是否已经清缓存
这里请先了解一下几个JVM命令
JPS,直接输入,然后会输出所有的java线程
C:\Users\hasee>jps
10048 test
16080
23584 Jps
22756 Launcher
21944
我这里使用的是10048’
jstat 查看虚拟机堆内存使用情况,输入这个命令的原因是让你去看看GC的时间,解释
C:\Users\hasee>jstat -gc 10048
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
512.0 512.0 0.0 128.0 3072.0 549.0 8192.0 1041.4 4864.0 3355.6 512.0 364.6 5 0.003 2 0.012 0.016
具体解释如下—这个命令然后可以推出吞吐量和停顿时间的关系
1
2
3
1
2
3
S0C:第一个幸存区的大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
更多命令解析,主要是这个命令的help不好用:
https://www.cnblogs.com/lizhonghua34/p/7307139.html 去这里
jmap:
C:\Users\hasee>jmap -heap 3764
Attaching to process ID 3764, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.66-b18
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 12582912 (12.0MB)
NewSize = 4194304 (4.0MB)
MaxNewSize = 4194304 (4.0MB)
OldSize = 8388608 (8.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 3145728 (3.0MB)
used = 496472 (0.47347259521484375MB)
free = 2649256 (2.5265274047851562MB)
15.782419840494791% used
From Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
To Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
PS Old Generation
capacity = 8388608 (8.0MB)
used = 8388448 (7.999847412109375MB)
free = 160 (1.52587890625E-4MB)
99.99809265136719% used
1684 interned Strings occupying 152632 bytes.
然后设置下JVM的大小,不然设置个500M,测试起来很痛苦,这是IDEA的
public class test {
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
//强引用,软引用,弱引用,虚引用
TestObj strognerReferenceObj = new TestObj();
TestObj softReferencObj = new TestObj();
TestObj weakReferenceObj = new TestObj();
TestObj padReferenceObj = new TestObj();
//强引用不用管,就是正常使用,什么时候GC了?这个function,OVER掉
SoftReference<TestObj> softReference = new SoftReference<TestObj>(softReferencObj);
WeakReference<TestObj> weakReference = new WeakReference<TestObj>(weakReferenceObj);
//虚引用,我觉得这个词是令人迷惑的,因为它其实是一种判断是否已经进入GC的形式,异步的
ReferenceQueue queue = new ReferenceQueue();
PhantomReference<TestObj> pf = new PhantomReference<TestObj>(padReferenceObj, queue);
//很多文章里面写的是没有引用,太令人困惑了,并且他们给的例子总是需要=null,才会消除引用,所以可以另一个角度去看,这是一种异步回调判断的
System.out.println("现在我们已经声明好了,所有引用类型");
System.out.println("强:" + strognerReferenceObj + " 软:" + softReference.get() + " 弱:" + weakReference.get() + " 虚:" + pf.get());
System.out.println("此时我们都是存在的,然后我们发起一次催促GC的请求,请注意,我只是催促,无法直接GC");
System.gc();
System.out.println("强:" + strognerReferenceObj + " 软:" + softReference.get() + " 弱:" + weakReference.get() + " 虚:" + pf.get());
System.out.println("这里虚引用一直为Null,但是padReferenceStr其实还存在的,先看软引用和弱引用的区别");
softReferencObj = null;
weakReferenceObj = null;
//请注意GC是催促的
System.gc();
while (weakReference.get() != null) {
Thread.sleep(1000);
System.out.println("正在等待GC。。。。");
}
System.out.println("强:" + strognerReferenceObj + " 软:" + softReference.get() + " 弱:" + weakReference.get() + " 虚:" + pf.get());
Thread pfThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
Object obj = queue.poll();
if (obj != null) {
try {
Field rereferent = Reference.class
.getDeclaredField("referent");
rereferent.setAccessible(true);
Object result = rereferent.get(obj);
System.out.println("gc will collect:"
+ result.getClass() + "\t"
+ result.toString());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
System.out.println("还没进GC等1s");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
pfThread.start();
padReferenceObj = null;
//这里使用join是为了
System.gc();
pfThread.join();
//软引用,最坑爹,先把虚引用写出来
System.out.println("弱引用就没有了,那如何将软引用也给清楚掉了?需要等堆区满");
LinkedList<TestObj> testObjs = new LinkedList<>();
LinkedList<TestObj> extraObjs = new LinkedList<>();
for (int i = 0; i < 50000; i++) {
TestObj testObj = new TestObj();
testObjs.add(testObj);
}
SoftReference<LinkedList<TestObj>> softReference1List = new SoftReference<LinkedList<TestObj>>(testObjs);
testObjs = null;
for (int i = 0; true; i++) {
System.gc();
//为什么我这里也加一个了,因为这个软GC,太坑爹了,找触发条件
if (softReference.get() == null) {
System.out.println("强:" + strognerReferenceObj + " 软:" + softReference.get() + " 弱:" + weakReference.get() + " 虚:" + pf.get());
break;
}
if (softReference1List.get() == null) {
System.out.println("软:" + softReference1List.get());
break;
}
extraObjs.add(new TestObj());
}
}
}
class TestObj {
int i;
HashMap<String, String> map = null;
public TestObj() {
map = new HashMap<>();
map.put("1", "1");
//为了填满堆区,这里会GC掉
/* for (int i = 0; i < 10; i++) {
HashMap<StringBuilder, StringBuilder> hashMap = new HashMap<>();
}*/
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
输出结果
现在我们已经声明好了,所有引用类型
强:algorithm.TestObj@238e0d81 软:algorithm.TestObj@31221be2 弱:algorithm.TestObj@377dca04 虚:null
此时我们都是存在的,然后我们发起一次催促GC的请求,请注意,我只是催促,无法直接GC
强:algorithm.TestObj@238e0d81 软:algorithm.TestObj@31221be2 弱:algorithm.TestObj@377dca04 虚:null
这里虚引用一直为Null,但是padReferenceStr其实还存在的,先看软引用和弱引用的区别
强:algorithm.TestObj@238e0d81 软:algorithm.TestObj@31221be2 弱:null 虚:null
gc will collect:class algorithm.TestObj algorithm.TestObj@41770d4b
弱引用就没有了,那如何将软引用也给清楚掉了?需要等堆区满
强:algorithm.TestObj@238e0d81 软:null 弱:null 虚:null
代码为主
代码值得说明的地方是:
我设置了2个软引用去测试,因为之前第一个我得测试方法有时候不出现结果,所以,我再写了一个软引用,这个软引用又很大,所以GC算法绝对会GC掉大的软引用
相关阅读
java游戏毕业设计-源代码+论文+开题下载一份基于java的五子棋游戏设计心急的人可以直接下载源码看了下载源代码以及开题论文一、
JavaScript之childNodes 和 children 区别
1、先让我们来看看childNodes的用法,以及是如何计算节点数量: 为什么输出是7而不是3呢?原来Internet Explorer 会忽略节点之间生
Java经典编程300例 PDF扫描版[78MB]http://pan.baidu.com/s/1gdGirZ1面向对象软件工程:使用UML、模式与 Java(第3版)完整版PDF[59MB]
public class Triangle { public boolean isTriangle(int a,int b,int c){ boolean flag = false; if (a+b>c&&a+c>b&&b+c>a
摘要 ThreadLocal是Java中的一个类,在Java 1.2版本加入,它的作者是Josh Bloch和Doug Lea。这篇文章会详细深入的分析ThreadLocal(基