你担心spring容器中scope为prototype的bean太大内存溢出吗?

你担心spring容器中scope为prototype的bean太大内存溢出吗?

提出假设

  • 之前一直担心spring的scope为prototype的bean在一些高并发的场景下,吃不消吗,甚至会内存溢出,这样的担心不是没有道理的,(以下是假设)因为这个类型的bean每一次都会产生新的实例,如果每个实例做一些时间比较长的任务,然后它会在这段时间常驻内存。那么它会爆炸吗?
  • 猜想1. 非并发的场景下,是正常的。因为它执行完之后在内存回收的时候总是可以被回收的
  • 猜想2.高并发的场景下,会内存溢出。因为在这段执行任务的期间,有多个Bean被初始化了,内存会不断增加。

验证猜想1

  • UserLogic.java

复制代码
  @Component
  // 保证singleton每次调用userLogic的时候都是最新的userLogic,
  // 如果没有配合上面的使用,获取这个bean的时候需要根据beanName获取,beanName需要加上前缀scopedTarget
  // 如getBean(scopedTarget.userLogic)
  @org.springframework.context.annotation.Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
  public class UserLogic {
      private Long timeMilis;

      private static int _100M = 100 * 1024 * 1024;

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

      public UserLogic(){
          timeMilis = (new Date()).getTime();
      }

      public void printTime() {
          System.out.println(timeMilis+"");
      }

      public Long getTimeMilis() {
          return timeMilis;
      }
  }
  • UserService.java

复制代码
  @Service
  public class UserService {
      @Autowired
      UserLogic logic;
      
      public void printNowTime(){
          logic.printTime();
      }
  }
  • Test.java

复制代码
  //TODO 查看如何创建scope注解的Logic的
              service = context.getBean("userService", UserService.class);
              logger.debug("===============================first================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(3);
              logger.debug("==============================second================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(3);

              logger.debug("=============================== end ================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(3);

              logger.debug("=============================== end ================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(3);

              logger.debug("=============================== end ================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(3);

              logger.debug("=============================== end ================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(3);

              logger.debug("=============================== end ================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(5);

              logger.debug("=============================== end ================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(5);

              logger.debug("=============================== end ================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(5);

              logger.debug("=============================== end ================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(5);

              logger.debug("=============================== end ================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(5);

              logger.debug("=============================== end ================================");
              service.printNowTime();
              TimeUnit.SECONDS.sleep(5);
  • 先测试下普通的,非高并发场景下的曲线

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

验证猜想2

  • 现修改UserLogic:::printTime()方法的代码

复制代码
  public void printTime() throws InterruptedException {
          Thread.sleep(1000);
          System.out.println(timeMilis+"");
      }
  • ConcurrentTest.java

复制代码
   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WuhulalaApplication.class);
          //context.start();
          final UserService service = context.getBean("userService", UserService.class);
          for (int i = 0; i < 20; i++) {
              new Thread(() ->{
                  try {
                      service.printNowTime();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }).start();
          }

          while(true){}
  • 果然报错

    Caused by: java.lang.OutOfMemoryError: Java heap space

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

总结

  • 以后使用scope的prototype时候一定要注意,但是本次测试也只是在极限情况下,比较难发生,但是也是有概率的

-----------------------------------------------------------------------------------

offer突击训练营简介:

1:针对不知道怎么面试,面试没有信心的小伙伴,我们会给你一个offer保障。

2:我们会监督你15-20天内把面试体系技术点掌握至少7成,这样足够你去找到满意的工作了。

3:我们是面向面试学习指导,不会带你们去写代码,会把项目真实开发的迭代过程和技术细节如何实现业务功能都详细教清楚,你能在面试中流畅表达清楚就行了,项目经验你不用担心(技术老师提供的真实项目经验肯定拿的出手),自己学和别人带着系统学,效率完全不一样。

详情请点击这里offer突击训练营,给你一个offer的保障,求职跳槽的看过来!

相关推荐
码出钞能力23 分钟前
linux内核模块的查看
linux·运维·服务器
考虑考虑39 分钟前
JDK9中的dropWhile
java·后端·java ee
想躺平的咸鱼干1 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
hqxstudying1 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·1 小时前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
春生野草2 小时前
关于SpringMVC的整理
spring
martinzh2 小时前
Spring AI 项目介绍
后端
Bug退退退1232 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
小皮侠2 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github
前端付豪2 小时前
20、用 Python + API 打造终端天气预报工具(支持城市查询、天气图标、美化输出🧊
后端·python