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 对象:没有内存泄漏。如果它一遍又一遍地使用同一个对象,那么该列表将会增长,并导致内存泄漏。