프로그래머로서 훈련하는 과정은 마치 판타지 소설 속 주인공과도 같습니다. 다양한 무술을 연습해야 할 뿐만 아니라 내면의 에너지를 키우는 것도 중요합니다. 무술은 주인공의 힘을 빠르게 향상시킬 수 있지만 내면의 에너지가 너무 낮으면 무술의 10분의 1도 발휘할 수 없습니다.
따라서 LZ는 디자인 패턴 등 외부 기술을 소개한 후 직접 내부 Qi 재배로 이동하여 모든 유인원 친구들과 JVM의 내용에 대해 논의했습니다.
원래 이 장에서는 GC와 관련된 내용을 소개해야 하는데, 그 전에 LZ가 여러분과 약간의 프로그래밍 요령에 대해 논의할 예정입니다. 물론 이 작은 트릭은 실제로 GC와 밀접한 관련이 있습니다.
혹시 JAVA 메모리 관련 글을 읽어보신 분 계시는지 모르겠네요.
제XX조: 개체를 사용한 후에는 개체를 명시적으로 null로 설정하세요.
원래 단어는 이렇지 않을 수도 있지만 의미는 같습니다. 단어에 설명된 의미는 앞으로 코드를 작성할 때 이렇게 작성해야 한다는 것입니다.
Object obj = new Object(); //to do something obj = null;
이 코드에는 약간의 C/C++ 스타일이 있습니다. obj=null은 C/C++에서 delete obj 또는 free(obj)를 대체합니다. 이는 GC를 사용하더라도 GC가 없으면 개체를 사용한 후 개체에 null 값을 할당해야 합니다.
먼저 LZ가 여기서 설명하고 싶은 것은 obj에 null 값을 할당하는 것이 실제로 C/C++의 삭제와 매우 다르다는 것입니다. LZ가 delete와 free를 대체한다고 말하는 이유는 바로 code 의 위치는 비슷합니다.
obj=null은 new Object()에 의해 생성된 인스턴스에서 참조 변수 obj의 연결을 끊는 작업만 수행합니다. 실제로 인스턴스가 차지하는 메모리 공간은 여전히 해제되지 않습니다.
이 제안이 나왔을 때 많은 블로거나 책 저자의 원래 의도는 (아마도 많은 블로거가 책에서 읽었을 것이기 때문입니다) 참조와 인스턴스 간의 연관성을 가능한 한 빨리 제거하여 가비지 중에 GC를 진행하도록 유도하는 것이었습니다. 컬렉션이 완료되면 인스턴스가 차지한 메모리가 해제됩니다. 어떤 경우에는 메모리 누수를 제거하기 위해 이 작업도 수행됩니다.
LZ는 개인적으로 이 제안을 하는 많은 블로거나 책 저자의 원래 의도는 주로 GC 원리와 메모리 관리에 노출되지 않은 프로그래머를 위한 것이라고 생각합니다. 불필요한 메모리 낭비로 이어지는 변수의 범위(메모리 누수가 발생하지 않는 한 메모리는 결국 GC에 의해 해제되기 때문에 이것이 주요 목적이 아니라고 개인적으로 생각합니다) 또는 심지어 메모리 누수까지 발생합니다.
그래서 일부 전문가들은 안전을 위해 이런 제안을 했습니다.
이를 고려하여 LZ는 모든 사람이 관련 지식을 습득한 후에는 이 제안을 완전히 무시할 수 있으며 그렇게 하면 분명히 코드의 명확성이 줄어들고 코딩의 부담이 증가할 것이라고 개인적으로 생각합니다. exchange는 존재하지 않을 수도 있는 메모리 누수를 방지하기 위한 것입니다.
다음은 개체에 null 값을 할당하지 않으면 메모리 누수가 발생하는 이유에 대한 설명입니다.
import java.util.Arrays; public class Stack { private static final int INIT_SIZE = 10; private Object[] datas; private int size; public Stack() { super(); datas = new Object[INIT_SIZE]; } public void push(Object data){ if (size == datas.length) { extend(); } datas[size++] = data; } public Object pop(){ if (size == 0) { throw new IndexOutOfBoundsException("size is zero"); } return datas[--size]; } private void extend(){ datas = Arrays.copyOf(datas, 2 * size + 1); } }
이 코드는 확장 가능한 길이를 가진 간단한 스택 구현입니다. 테스트 코드를 작성해 보면 문제가 없다는 것을 알 수 있습니다. 하지만 죄송합니다. 여기에는 일부 개체나 참조가 null 값으로 설정되지 않아 발생하는 명백한 "메모리 누수"가 있습니다.
아직 못 보신 분들은 LZ가 살짝 알림을 드리고 깨닫게 될 거예요. 이 코드에서 배열의 개체는 무한히 증가하며 스택의 요소가 팝되어도 감소하지 않습니다. 감소하는 것은 외부에 표시되는 스택의 크기뿐입니다. 극단적인 시나리오를 가정해 보겠습니다. 100만 개의 개체를 스택에 넣었고 최종적으로 999,999개가 사용되었습니다. 외부에서는 스택에 사용 가능한 개체가 하나만 남아 있지만 스택에는 여전히 100만 개의 개체에 대한 참조가 있습니다. JVM이 살아남을 수 있다면 분명히 당신을 죽음에 이르게 할 것입니다.
우리가 부족한 점은 객체에 null 값을 할당하는 단계이므로 pop 메소드를 다음 메소드로 변경해야 하며, ArrayList에서 Remove 메소드의 소스코드를 보면 알 수 있습니다. 비슷한 생각.
public Object pop(){ if (size == 0) { throw new IndexOutOfBoundsException("size is zero"); } Object data = datas[--size]; datas[size] = null; return data; }
这个内存泄露是非常隐蔽的,而且实际使用当中不一定就能发现,因为随着Stack对象的回收,整个数组也会被回收,到时内存泄露就被掩盖了。
所以个人觉得上述的那个建议是完全没有必要的,就算遵从了上面的建议,如果对内存管理不熟悉的话,也不会想到上面这个代码中的问题。如果想彻底的避免内存泄露的发生,机械式的主动将对象赋为空值,并不是一个可以从根本上解决问题的办法。
真正能够解决问题的办法,就是掌握好GC的策略与原理,定义一个变量时多注意变量的作用域,如此才可以更好的避免内存泄露。
所以学好GC原理还是很有必要的,希望准备走JAVA之路的朋友,尤其是从培训机构出来的猿友们(此处没有鄙视培训机构出来的猿友们的意思,因为LZ本人也是半路出家,从培训机构走上编程之路的程序猿之一),一定不要只专注于各个框架的使用以及业务的深入,虽然这些事很有必要,但并不是全部。
follow me and go the memory world 吧(语法都是浮云)。
以上就是JVM内存管理------杂谈(借此也论一论obj=null)的内容,更多相关内容请关注PHP中文网(www.php.cn)!