最近在看JVM优化相关的书,我使用jdk8,设置最大堆内存为10MB,在idea中执行以下代码
期望最后一行代码打印的结果为“null”,但是结果只有两种,要么软引用的user对象仍然存在,要么报内存溢出,大家能否帮我分析一下可能是什么原因
import java.lang.ref.SoftReference;
public class SoftRef {
public static class User{
public int id;
public String name;
public User(int id,String name){
this.id = id;
this.name =name;
}
@Override
public String toString(){
return "{id="+String.valueOf(id)+",name="+name+"}";
}
}
public static void main(String[] args) {
User u = new User(1,"RYU");
SoftReference<User> userSoftReference = new SoftReference<>(u);
u = null;
System.out.println(userSoftReference.get());
System.gc();
System.out.println("After GC:");
System.out.println(userSoftReference.get());
byte[] b=new byte[1024*925*7];//约申请7MB空间
System.gc();
System.out.println(userSoftReference.get());
}
}
内存溢出:
除了你显式分配的约7M byte,User变量,Reference变量等,JVM自身也会占用一些空间,所以10M并不能确保满足程序正常运行,有可能在 new byte[1024*925*7];
时没有足够的空间就溢出了。
为什么userSoftReference.get())
不为null:
因为GC不是外部能够控制的,是jvm运行过程中,在适当的时候才会进行的。虽然你执行了System.gc()
,并不代表jvm已经进行了垃圾回收。另外即使进行了垃圾回收,也不能确保jvm会因为内存不足将SoftReference对象回收掉,你这个User占用的内存也是非常小。
我猜想你是为了验证WeakReference会快速回收,而SoftReference在内存不足才回收?这样的话,我建议可以这样测试:
JVM分配10M内存,代码中逐步增加内存,一直观察,譬如:
public static class User{
public int id;
public String name;
private byte[] b = new byte[1024 * 1024]; //PS: 这里纯粹是为了让User分配内存更大
public User(int id,String name){
this.id = id;
this.name =name;
}
@Override
public String toString(){
return "{id="+String.valueOf(id)+",name="+name+"}";
}
}
public static void main(String[] args) {
List<SoftReference> ulist = new ArrayList<>();
while (true) {
System.out.println("Now look at what we get from ref:");
ulist.add(new SoftReference(new User(1, "test")));//一直new新的user对象,导致内存不足触发GC
ulist.forEach(ref -> System.out.println(ref.get())); //不出意外,list元素会越来越多,但是get到的基本都是null
}
}
如果是单纯测试软引用,可以参考以下代码(VM参数:-Xmx24m):
public class V02_SoftReference {
// 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。
// 只要垃圾回收器没有回收它,该对象就可以被程序使用。
// 软引用可用来实现内存敏感的高速缓存。
// 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
//-Xmx24m
public static void main(String[] args) throws IOException, InterruptedException {
// 10m
SoftReference<byte[]> sr = new SoftReference<byte[]>(new byte[1024 * 1024 * 10]);
System.out.println(sr.get());
System.gc();
TimeUnit.MILLISECONDS.sleep(500);
System.out.println(sr.get());
// 15m
// 再分配一个数组,heap将装不下,这时候系统会垃圾回收,先回收一次,如果不够,会把软引用干掉
byte[] m2 = new byte[1024 * 1024 * 15];
System.out.println(sr.get());
}
}