作者: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执行完任务后立马释放了内存,所以曲线如下图所示[直上直下]