你担心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的保障,求职跳槽的看过来!

相关推荐
独立开阀者_FwtCoder2 分钟前
"页面白屏了?别慌!前端工程师必备的排查技巧和面试攻略"
java·前端·javascript
Touper.7 分钟前
JavaSE -- 泛型详细介绍
java·开发语言·算法
狂师10 分钟前
啥是AI Agent!2025年值得推荐入坑AI Agent的五大工具框架!(新手科普篇)
人工智能·后端·程序员
星辰大海的精灵12 分钟前
使用Docker和Kubernetes部署机器学习模型
人工智能·后端·架构
MikeWe15 分钟前
C++宏的解析:从基础语法到实战场景
后端
向往技术的猫菜20 分钟前
Java必需要会的MySQL知识
后端
Frank_zhou23 分钟前
Java代码是如何运行起来的
后端
Victor35623 分钟前
MySQL(121)如何处理死锁问题?
后端
亚洲第一中锋_哈达迪23 分钟前
深入剖析 go-zero 分布式缓存
后端
静若繁花_jingjing24 分钟前
Redis线程模型
java·数据库·redis