spring容器中scope为prototype时会导致内存溢出吗

作者:wuhulala  
来源:CSDN  
原文:https://blog.csdn.net/u013076044/article/details/78035298 

 

我在原作者的基础上做了一些代码的调整,可能会遇到机器内存比较大,无法出现OutOfMemery的情况,实验的时候可以多加一些线程数量

 

提出假设

之前一直担心spring的scope为prototype的bean在一些高并发的场景下,吃不消吗,甚至会内存溢出,这样的担心不是没有道理的,(以下是假设)因为这个类型的bean每一次都会产生新的实例,如果每个实例做一些时间比较长的任务,然后它会在这段时间常驻内存。那么它会爆炸吗?*

  •     猜想1. 非并发的场景下,是正常的。因为它执行完之后在内存回收的时候总是可以被回收的
  •     猜想2.高并发的场景下,会内存溢出。因为在这段执行任务的期间,有多个Bean被初始化了,内存会不断增加。

验证猜想1

下面我们大胆测试以下(单线程情况下)

/**
 * proxyMode采用了cglib动态代理,这样每次调用这个类的方法时,都会生成一个新的对象
 */
@Component
@org.springframework.context.annotation.Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Node {
    private Date time;

    //这一块的大小可以根据自己的机器配置决定
    private static int _200M = 200 * 1024 * 1024;

    private byte[] memory = new byte[_200M];

    public Node(){
        time = new Date();
    }

    public void printInfo() {
        System.out.println(new Date());
        System.out.println(this.toString());
        try {
//        Thread.sleep(10000);
//      } catch (InterruptedException e) {
//        e.printStackTrace();
//      }
    }

    public Date getTimeMilis() {
        return time;
    }

}

 

@Service
public class TestService {

    @Autowired
    Node node;

    public void test(){

      try {
      logger.info("===============================第一次================================");
      userLogic.printInfo();
      TimeUnit.SECONDS.sleep(5);
      logger.info("===============================结束================================");


      logger.info("===============================第二次================================");
      userLogic.printInfo();
      TimeUnit.SECONDS.sleep(5);
      logger.info("===============================结束================================");


      logger.info("===============================第三次================================");
      userLogic.printInfo();
      TimeUnit.SECONDS.sleep(5);
      logger.info("===============================结束================================");


      logger.info("===============================第四次================================");
      userLogic.printInfo();
      TimeUnit.SECONDS.sleep(5);
      logger.info("===============================结束================================");


      logger.info("===============================第五次================================");
      userLogic.printInfo();
      TimeUnit.SECONDS.sleep(5);
      logger.info("===============================结束================================");


      logger.info("===============================第六次================================");
      userLogic.printInfo();
      TimeUnit.SECONDS.sleep(5);
      logger.info("===============================结束================================");


      logger.info("===============================第七次================================");
      userLogic.printInfo();
      TimeUnit.SECONDS.sleep(5);
      logger.info("===============================结束================================");


      logger.info("===============================第八次================================");
      userLogic.printInfo();
      TimeUnit.SECONDS.sleep(5);
      logger.info("===============================结束================================");


      logger.info("===============================第九次================================");
      userLogic.printInfo();
      TimeUnit.SECONDS.sleep(5);
      logger.info("===============================结束================================");


      logger.info("===============================第十次================================");
      userLogic.printInfo();
      TimeUnit.SECONDS.sleep(5);
      logger.info("===============================结束================================");
    } catch (Exception e) {
    }
    }

   
}

 

先测试下普通的,非高并发场景下的曲线
 

可以看到,被回收掉了,与预想的一样


验证猜想2

现修改TestService::printTime()方法的代码,把他的注释给去掉,然后改用多线程的方式处理

/**
 * proxyMode采用了cglib动态代理,这样每次调用这个类的方法时,都会生成一个新的对象
 */
@Component
@org.springframework.context.annotation.Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Node {
    private Date time;

    //这一块的大小可以根据自己的机器配置决定
    private static int _200M = 200 * 1024 * 1024;

    private byte[] memory = new byte[_200M];

    public Node(){
        time = new Date();
    }

    public void printInfo() {
        System.out.println(new Date());
        System.out.println(this.toString());
        try {
          Thread.sleep(10000);
        } catch (InterruptedException e) {
          e.printStackTrace();
       }
    }

    public Date getTimeMilis() {
        return time;
    }

}
@Service
public class TestService {

    @Autowired
    Node node;

    public void test(){
        for (int i = 0; i < 50; i++) {
            new Thread(
                () -> {
                    node.printInfo();
                }
            ).start();
        }
    }   
}

果然报错

只不过这些bean执行完任务后立马释放了内存,所以曲线如下图所示[直上直下]

 


总结

以后使用scope的prototype时候一定要注意,虽然这里测试的是极限情况,但是也是有概率的。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值