出假设 之前一直担心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+""); } 1 2 3 4 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时候一定要注意。。。。 但是本次测试也只是在极限情况下,比较难发生。。。 但是也是有概率的