Java 内存泄漏 - 静态与 Bean
Java Memory Leak - Static vs Beans
所以我仍在学习一般的内存管理,而不仅仅是 Java。我读过这个 Baeldung article.
文章显示了以下代码的示例:
public class StaticTest {
public static List<Double> list = new ArrayList<>();
public void populateList() {
for (int i = 0; i < 10000000; i++) {
list.add(Math.random());
}
Log.info("Debug Point 2");
}
public static void main(String[] args) {
Log.info("Debug Point 1");
new StaticTest().populateList();
Log.info("Debug Point 3");
}
}
如果 list
是静态的 Java 仍然保留对象而不是垃圾收集,我在示例中得到了这一点。但是如果我们删除 static
关键字,在我们离开 populateList
方法后它将被垃圾收集。
但是如果场景是 Bean 呢?考虑来自 Spring 启动项目的这个例子:
@RestController
public class UserController {
@Autowired
private UserService userService;
private List<User> userList = new ArrayList<>();
@GetMapping("/users")
public ResponseEntity<List<User>> getAllUser() {
List<User> userList = userService.findAll();
for(User u: userList) {
this.userList.add(u);
}
return ResponseEntity.ok(userList);
}
}
因为它用 @RestController
注释,所以将创建一个 bean,不过在我自己的测试中,这不会导致内存泄漏,或者至少堆内存不会像static list
即使对象数相同。在我对 Bean 的理解中,userList
应该仍然在内存中并且不应该被垃圾收集,那有什么区别呢?
你看错了角度。最终决定垃圾收集器是否收集对象的不是static或是bean
唯一的标准是:该对象是否仍被认为是 活着?!
当可以从 运行 个线程的上下文中“到达”对象时,对象被认为是活动的。
换句话说:静态 成员被相应的class 对象引用。那些又(很可能)被加载 class 的 ClassLoader 引用。因此 static 成员通常还活着,不会被收集。
对于您的 bean 示例,要点是:这是一个将在外部 REST 请求进入时调用的方法。接下来:处理请求,准备响应数据,发送响应数据和答案。
现在:响应对象引用了 bean 对象。但在发送响应后,不再引用响应。因此没有对 bean 的引用。因此,该列表对象不再存在,列表、bean、响应,它们都受到垃圾收集的影响。
但是:是的,那个 UserController 实例一直在向 字段 添加用户对象。因此存在内存泄漏的可能性。
如果 Spring 框架 丢弃 这些 UserContext 对象:没有内存泄漏。如果它一遍又一遍地使用同一个对象,那么该列表将会增长,并导致内存泄漏。
所以我仍在学习一般的内存管理,而不仅仅是 Java。我读过这个 Baeldung article.
文章显示了以下代码的示例:
public class StaticTest {
public static List<Double> list = new ArrayList<>();
public void populateList() {
for (int i = 0; i < 10000000; i++) {
list.add(Math.random());
}
Log.info("Debug Point 2");
}
public static void main(String[] args) {
Log.info("Debug Point 1");
new StaticTest().populateList();
Log.info("Debug Point 3");
}
}
如果 list
是静态的 Java 仍然保留对象而不是垃圾收集,我在示例中得到了这一点。但是如果我们删除 static
关键字,在我们离开 populateList
方法后它将被垃圾收集。
但是如果场景是 Bean 呢?考虑来自 Spring 启动项目的这个例子:
@RestController
public class UserController {
@Autowired
private UserService userService;
private List<User> userList = new ArrayList<>();
@GetMapping("/users")
public ResponseEntity<List<User>> getAllUser() {
List<User> userList = userService.findAll();
for(User u: userList) {
this.userList.add(u);
}
return ResponseEntity.ok(userList);
}
}
因为它用 @RestController
注释,所以将创建一个 bean,不过在我自己的测试中,这不会导致内存泄漏,或者至少堆内存不会像static list
即使对象数相同。在我对 Bean 的理解中,userList
应该仍然在内存中并且不应该被垃圾收集,那有什么区别呢?
你看错了角度。最终决定垃圾收集器是否收集对象的不是static或是bean
唯一的标准是:该对象是否仍被认为是 活着?!
当可以从 运行 个线程的上下文中“到达”对象时,对象被认为是活动的。
换句话说:静态 成员被相应的class 对象引用。那些又(很可能)被加载 class 的 ClassLoader 引用。因此 static 成员通常还活着,不会被收集。
对于您的 bean 示例,要点是:这是一个将在外部 REST 请求进入时调用的方法。接下来:处理请求,准备响应数据,发送响应数据和答案。
现在:响应对象引用了 bean 对象。但在发送响应后,不再引用响应。因此没有对 bean 的引用。因此,该列表对象不再存在,列表、bean、响应,它们都受到垃圾收集的影响。
但是:是的,那个 UserController 实例一直在向 字段 添加用户对象。因此存在内存泄漏的可能性。
如果 Spring 框架 丢弃 这些 UserContext 对象:没有内存泄漏。如果它一遍又一遍地使用同一个对象,那么该列表将会增长,并导致内存泄漏。