To avoid memory leaks, I've listed as far as I know when garbage collection works and when it doesn't.
A function that automatically destroys an object at Java's discretion when it is no longer handled by any variable. The "finalize () method" destroys the object, but in Java, even if this method is defined, the timing cannot be managed.
Since I confirmed it with a simple process, I lowered the heap area to make it easier for memory leaks. (Like a memory leak at 2M) Initial heap size-Xms1m Maximum heap size-Xmx2m
Since "assigning null to a variable = the variable does not represent any object", it works when all the variables representing a certain object become null. Substitute null = It's like saying "I don't use this anymore", so Garbage Collection will judge that it is unnecessary.
public class AddList01 {
public static void main(String[] args) {
//Process 1
List<String> list1 = new ArrayList<>();
addList(list1);
list1 = null;
//Process 2
List<String> list2 = new ArrayList<>();
addList(list2);
list2 = null;
}
private static void addList(List<String> list) {
for (int i = 0; i < 100000; i++) {
list.add("a");
}
}
}
Garbage collection works when the variable that handles the object is no longer listed. "I saw the whole sauce, but I haven't dealt with it since then, so it's okay to throw away the contents."
public class AddList02 {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
//Process 1
for (int i = 0; i < 100000; i++) {
list1.add("a");
}
//Process 2
for (int i = 0; i < 100000; i++) {
list2.add("b");
}
}
}
Garbage collection works when a completed object in a loop, such as declared in a loop or instantiated, exits the loop. This is because variables declared inside the loop cannot be handled outside the loop.
public class AddList03 {
public static void main(String[] args) {
try {
//Process 1
for (int i = 0; i < 10; i++) {
List<String> list1 = new ArrayList<>();
for (int j = 0; j < 100000; j++) {
list1.add("a");
}
}
//Process 2
List<String> list2 = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list2 = new ArrayList<>();
for (int j = 0; j < 100000; j++) {
list2.add("b");
}
}
//Process 3
int i = 0;
while (i < 10) {
List<String> list3 = new ArrayList<>();
for (int j = 0; j < 100000; j++) {
list3.add("c");
}
i++;
}
//Process 4
List<String> list4 = new ArrayList<>();
for (int j = 0; j < 100000; j++) {
list4.add("d");
}
} catch (Exception e) {
e.printStackTrace();
}
//Process 5
List<String> list5 = new ArrayList<>();
for (int j = 0; j < 100000; j++) {
list5.add("e");
}
}
}
By the way, when the variable "list2" is handled after the loop, only the instance of the last loop is left.
public class AddList031 {
public static void main(String[] args) {
List<String> list2 = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list2 = new ArrayList<>();
for (int j = 0; j < 50000; j++) {
list2.add("b");
}
}
System.out.println(String.join("", list2));
}
}
It is the same principle as the loop of ③. However, the value referred to by the argument and the return value remain.
public class AddList04 {
public static void main(String[] args) {
addList();
addList();
addList();
}
private static void addList() {
List<String> list = new ArrayList<>();
for (int j = 0; j < 100000; j++) {
list.add("a");
}
}
}
In case (2) that works, the object that is no longer handled was discarded, but if you refer to the object with another method, garbage collection will not work. Why is this?
public class AddList05 {
public static void main(String[] args) {
//Process 1
List<String> list1 = new ArrayList<>();
addList(list1);
//Process 2
List<String> list2 = new ArrayList<>();
addList(list2);
}
private static void addList(List<String> list) {
for (int i = 0; i < 100000; i++) {
list.add("a");
}
}
}
Since it is used in various places in the class, it is a case where it is described in the field so that there are not many arguments. It seems that the scope of the list is too wide to decide that garbage collection is unnecessary.
public class AddList06 {
private List<String> list1 = new ArrayList<>();
private List<String> list2 = new ArrayList<>();
public static void main(String[] args) {
AddList06 addList06 = new AddList06();
//Process 1
for (int i = 0; i < 100000; i++) {
addList06.list1.add("a");
}
//Process 2
for (int i = 0; i < 100000; i++) {
addList06.list2.add("a");
}
}
}
Even if the instance is not created by the main method, the instance is created by the called method and the one received as the return value remains.
public class AddList07 {
public static void main(String[] args) {
//Process 1
List<String> list = addList();
//Process 2
list = addList();
//Process 3
list = addList();
}
private static List<String> addList() {
List<String> list = new ArrayList<>();
for (int i = 0; i < 50000; i++) {
list.add("a");
}
return list;
}
}
Even if you use the list method to delete a value that is no longer used in the list you are using, it does not mean that it is null, so the object seems to remain referenced.
public class AddList08 {
public static void main(String[] args) {
//Process 1
List<String> list1 = new ArrayList<>();
addList(list1);
list1.clear();
//Process 2
List<String> list2 = new ArrayList<>();
addList(list2);
for (int i = 0; i < list2.size(); i++) {
list2.remove(i);
}
//Process 3
List<String> list3 = new ArrayList<>();
addList(list3);
}
private static void addList(List<String> list) {
for (int i = 0; i < 50000; i++) {
list.add("a");
}
}
}
You might think it's not that simple, but for the time being ・ "As much as possible, divide the process into small methods and have it locally" ・ "Use where you can reuse without creating variables and instances in vain" ・ "Refrain from variable declaration in the field" I felt that.
After that, if there is processing such as SQL acquisition and registration from DB, will it be divided according to the processing purpose? It may take time if there are multiple SQLs, but I thought it was better than the processing slowing down.
Recommended Posts