首页 新闻 会员 周边

java 软引用为什么会导致内存溢出

0
悬赏园豆:50 [待解决问题]

最近在看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());
}

}

赛博朋克水管工的主页 赛博朋克水管工 | 初学一级 | 园豆:152
提问于:2020-04-23 11:42
< >
分享
所有回答(2)
1
  • 内存溢出:
    除了你显式分配的约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
            
        }
    }


。淑女范erり | 园豆:961 (小虾三级) | 2020-04-23 14:01
0

如果是单纯测试软引用,可以参考以下代码(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());
  }

}

宗离 | 园豆:206 (菜鸟二级) | 2020-05-05 10:01
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册