So I'm still learning about memory management in general, not only in Java. I've read in this Baeldung article.
The article shows an example of the following code:
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");
}
}
I get that in the example if the list is static Java still keeps the object and not garbage collects it. But if we remove the static keyword, after we leave the populateList method it'll be garbage collected.
But what if the scenario is of a Bean. Consider this example from a Spring Boot project:
@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);
}
}
As it is annotated with the @RestController a bean will be created, in my own testing though, this doesn't cause a memory leak or at least the heap memory doesn't get as big as the static list even if the object count is the same. In my understanding of a Bean the userList should still be in memory and shouldn't be garbage collected, so what's the difference?
CodePudding user response:
You are looking at it from the wrong angle. In the end, it is not static or being a bean that determines whether the garbage collector collects an object.
The only criteria is: is that object still considered alive?!
Objects are considered alive when they can be "reached" from the context of the running thread(s).
In other words: static members are referenced by the corresponding class objects. Those in turn are (most likely) referenced by the ClassLoader that loaded the class. Therefore static members are typically alive, and won't be collected.
For your bean example, the point is: this is a method that will be invoked when an external REST request comes in. Next: request gets handled, response data gets prepared, response data is SEND out with the answer.
Now: the bean object was referenced by the response object. But after the response has been sent, there is no reference to the response any more. Thus no reference to the bean. Thus that list object is no longer alive, and list, bean, response, they all are subject to garbage collection.
But: yes, that UserController instance keeps adding User objects to that field. Thus there is a potential for a memory leak.
If the Spring frameworks discards these UserContext objects: no memory leak. If it keeps using the same object over and over again, then that list will grow, and cause a memory leak.
