프로그램이 객체, 어레이 등과 같은 참조 유형 엔티티를 작성하면 시스템은 힙 메모리의 객체에 대한 메모리 조각을 할당하고 객체는이 메모리에 저장됩니다. 이 메모리가 더 이상 참조 변수에 의해 참조되지 않으면 메모리 조각이 쓰레기가되어 쓰레기 수집 메커니즘이 재활용되기를 기다립니다. 가비지 수집 메커니즘에는 세 가지 특성이 있습니다.
쓰레기 수집 메커니즘은 힙 메모리의 개체를 재활용하는 데 책임이 있으며, 물리적 자원 (예 : 데이터베이스 연결, 열린 파일 리소스 등)과 같은 물리적 자원을 재활용하지 않으며, 객체를 만드는 방식으로 (예 : 로컬 메소드에서 malloc를 호출하는 메모리에 의해 적용되는 메모리와 같은) 메모리를 재활용하지 않습니다.
이 프로그램은 쓰레기 수집의 운영을 정확하게 제어 할 수 없으므로 쓰레기 수집에만 권장 할 수 있습니다. 두 가지 권장 방법이 있습니다 : System.gc () 및 runtime.getRuntime (). gc ()
쓰레기 수집 이전에는 최종화 () 메소드가 항상 먼저 호출되지만 쓰레기 수집 시간과 동일하며 Finalize () 메소드도 확실하지 않습니다.
위의 세 가지 특성과 관련하여 세 가지 문제가 있습니다.
1. 청소 작업은 객체를 만드는 방식 이외의 방식으로 메모리 및 기타 물리적 자원을 확보하기 위해 수동으로 수행되어야합니다. 만료 된 객체 참조를 제거하기 위해주의하십시오. 그렇지 않으면 OOM이 발생할 수 있습니다.
수동 청소는 일반적으로 시도와 같은 코드 구조를 사용합니다 ... 마지막으로 ...
예는 다음과 같습니다.
import java.io.fileInputStream; import java.io.filenotFoundException; import java.io.ioException; public class manualclear {public static void main (String [] args) {fileInputStream fileInputStream = null; try {fileInputStream = new FileInputStream ( "./ SRC/MANUALCLEAR.JAVA"); } catch (filenotfoundException e) {System.out.println (e.getMessage ()); e.printstacktrace (); 반품; } try {byte [] bbuf = new Byte [1024]; int hasread = 0; try {while ((hasread = fileInputStream.read (bbuf))> 0) {System.out.println (new String (bbuf, 0, hasread)); }} catch (ioexception e) {e.printstacktrace (); }} 마침내 {try {fileInputStream.close (); } catch (ioexception e) {e.printstacktrace (); }}}}일반적으로 만료 된 객체를 참조하여 발생하는 3 가지 일반적인 OOM 사례가 있습니다. 이 세 가지 사례는 일반적으로 감지하기 쉽지 않으며 짧은 시간 내에 실행하는 데 아무런 문제가 없습니다. 그러나 오랜 시간이 지나면 유출 된 물체의 수는 결국 프로그램이 충돌하게됩니다.
클래스가 메모리 자체를 관리하면 다음과 같이 메모리 누출에주의해야합니다.
import java.util.arrays; import java.util.emptystackexception; 클래스 스택 {private object [] elements; 개인 INT 크기; 개인 정적 최종 int default_inital_capacity = 16; public stack () {elements = new Object [default_inital_capacity]; } public void push (Object e) {ensurecapacity (); 요소 [size ++] = e; } public Object POP () {if (size == 0) {새 nict emptystackexception (); } 반환 요소 [-크기]; } private void ensurecApacity () {if (elements.length == size) {elements = arrays.copyof (요소, 2 * size + 1); }}} public class stackdemo {public static void main (String [] args) {스택 스택 = 새 스택 (); for (int i = 0; i <10000; i ++) {stack.push (new Object ()); } for (int i = 0; i <10000; i ++) {stack.pop (); }}}메모리 누출의 이유는 스택의 다른 객체가 더 이상 참조되지 않더라도 스택 클래스의 요소 [] 배열은 여전히 이러한 객체에 대한 참조를 보유하여 객체가 쓰레기 수집에 의해 재활용되지 않기 때문입니다. 따라서 클래스가 자체적으로 메모리를 관리해야 할 때 내부적으로 유지되는 만료 된 참조가 제 시간에 해석되는지 여부를 조심하십시오. 이 예에서는 스택이 릴리스 된 후에 만 표시된 것이 표시됩니다.
요소 [size] = null;
캐시는 메모리 누출에주의해야합니다. 이 상황은 일반적으로 객체를 캐시에 넣으면 오랫동안 사용되지 않으면 잊기 쉽습니다. 일반적으로 WakeHashMap을 사용하여 캐시를 나타낼 수 있습니다. 캐시의 항목이 만료되면 자동으로 삭제할 수 있습니다. 또는 버퍼에서 만료 된 항목을 지우기 위해 배경 스레드에 의해 주기적으로 실행될 수 있습니다.
청취자 또는 콜백 등록은 등록하지 않도록 가장 잘 표시됩니다.
2. 결승에 전화하지 마십시오 () 수동으로 가비지 수집가에게 호출됩니다.
3. 객체가 올바르게 청소되지 않았다는 것을 알기 위해 최종 조건을 판단하는 것이 아니라면 finalize () 메소드를 사용하지 마십시오. 수동으로 잊어 버린 통화를 정리할 때 시스템 리소스를 정리하기 위해 보안 네트워크로 사용됩니다. 지연된 청소를 청소해서는 안됩니다. 잊혀진 청소 자원에 대한 정보를 동시에 기록하면 나중에 오류를 발견하고 잊혀진 청소 코드를 제 시간에 수정하는 것도 편리합니다. 객체의 로컬 방법에 의해 얻은 비판적 시스템 자원을 자유롭게합니다.
Finalize () 메소드는 정확하게 보장되지 않으므로 주요 리소스를 해제하지는 않지만 위에서 언급 한 세 가지 경우에는 사용될 수 있습니다. 첫 번째 사례는 다음과 같습니다.
클래스 북 {boolean Checkout = false; 공개 도서 (부울 결제) {this.checkout = Checkout; } public void checkin () {checkout = false; } @override protected void inderize () 던지기 가능 {if (checkout) {system.out.println ( "error : checkout"); }}} public class finalizecheckobjercuse {public static void main (String [] args) {new Book (true); System.gc (); }}실행 결과 :
오류 : 체크 아웃
예제의 책 객체는 공개되기 전에 체크인 상태에 있어야합니다. 그렇지 않으면 공개 할 수 없습니다. Finalize의 구현은 불법 객체를 제 시간에 발견하거나 직접적으로 직접 발견하는 데 도움이 될 수 있습니다. 참조 변수를 사용하여 Finalize에서 직접 참조하여 도달 상태를 다시 입력 한 다음 다시 처리 할 수 있습니다.
또 다른 점에 주목해야 할 또 다른 점은 서브 클래스가 상위 클래스의 최종 메소드를 무시하지만 수동으로 호출하는 것을 잊어 버리면 서브 클래스의 파일링 프로세스에 예외가있어서 Super.Finalize가 실행되지 않으면 부모 클래스의 최종 방법이 호출되지 않습니다.
다음과 같이 :
class parent {@override protected void finalize () trows strowable {system.out.println (getClass (). getName () + "finalize start"); }} class son은 parent {@override protected void intrindize () trows {system.out.println (getClass (). getName () + "finalize start"); }} public class superfinalizelost {public static void main (String [] args) {new Son (); System.gc (); }}실행 결과 :
아들은 시작을 마무리합니다
또는
class parent {@override protected void finalize () trows strowable {system.out.println (getClass (). getName () + "finalize start"); }} class son은 parent {@override protected void intrindize () trows {system.out.println (getClass (). getName () + "finalize start"); int i = 5 / 0; super.finalize (); }} public class superfinalizelost {public static void main (String [] args) {new Son (); System.gc (); }}실행 결과 :
아들은 시작을 마무리합니다
두 번째 경우, 당신은 시도를 사용할 수 있습니다 ... 마지막으로 ... 구조를 해결하기 위해 구조를 해결할 수 있지만 첫 번째 경우 End Method Guardian이라는 메소드를 사용하는 것이 좋습니다. 예는 다음과 같습니다
class parent2 {private final object finalizeguardian = new Object () {protected void finalize () 던질 수있는 {system.out.println ( "여기서 부모 클래스 종료 방법의 논리 실행"); }; };} class son2는 parent2 {@override protected void intrownize () throws strowable {system.out.println (getClass (). getName () + "finalize start"); int i = 5 / 0; super.finalize (); }} public class finalizeguardian {public static void main (String [] args) {new Son2 (); System.gc (); }}실행 결과 :
여기에서 부모 클래스 종료 방법에서 논리를 실행하십시오.
SON2 시작을 마무리합니다
이를 통해 부모 클래스의 최종 방법에 필요한 작업이 실행되도록합니다.
위의 내용은이 기사에 관한 모든 것입니다. 모든 사람의 학습에 도움이되기를 바랍니다.