Java 메모리 누수를 방지하는 방법
프로그램이 일부 대상을 더 이상 사용하지 않지만, 인용되고 있을 때 메모리 유출이 발생합니다.이 때문에 쓰레기 수집기에서 제거될 자격이 없다.시간의 흐름에 따라 응용 프로그램이 계속 실행되고, 사용 가능한 메모리가 가득 찰 때까지 이러한 대상이 점점 더 많이 만들어진다.결국 OutOfMemory 오류로 인해 복구가 불가능할 수 있습니다.
메모리 유출은 자바 응용 프로그램에서 가장 까다로운 문제 중 하나이다.그것들은 간과되기 쉽고 들키기도 어렵다.
응용 프로그램에 메모리 유출이 있는지 어떻게 알 수 있습니까
만약:
내가 말한 바와 같이 메모리 유출을 검출하기 어려우니 피하는 것이 가장 좋다.나는 너희들에게 흔히 볼 수 있는 메모리 유출 장면과 그것들을 방지하는 좋은 실천을 알려줄 것이다.
1. 정전장 대량 사용
이것은 전형적인 메모리 유출 장면으로 이 장면에서 자바 대상을 만들 때 방출되지 않았다.정적 참조는 JVM의 전체 라이프 사이클에 지속되므로 메모리에서 객체를 지울 수 없습니다.
예를 들면 다음과 같습니다.
public class StaticFieldMemoryLeak {
private static List<Integer> integers = new ArrayList<Integer>();
public void insertIntegers() {
for (int i = 0; i < 100000000; i++) {
integers.add(i);
}
}
public static void main(String[] args) {
StaticFieldMemoryLeak staticFieldMemoryLeak = new StaticFieldMemoryLeak();
staticFieldMemoryLeak.insertIntegers();
System.out.println("Done with inserting integers");
}
}
우리가 '정수 삽입 완료' 를 쓰는 줄에 도착했을 때, 우리는 더 이상 우리의 목록을 필요로 하지 않는다.그러나 이 목록은 정적 필드이기 때문에 스팸 수집기는 그것을 영원히 수집하지 않습니다. 코드를 사용한 후에도 마찬가지입니다.물론 이것은 작은 예로 매우 간단한 절차가 있다.그러나 만약에 대형 응용 프로그램이 있다면 복잡한 절차가 있고 불필요한 정적 변수가 한 무더기 있다.이 경우 다른 일에 사용할 수 있는 자원을 대량으로 사용하고 메모리를 소모할 수 있습니다.
지금 우리는 같은 예를 보겠지만, 이번에는 목록을 국부 변수로 성명할 것이다.
public class StaticFieldMemoryLeak {
public void insertIntegers() {
List<Integer> integers = new ArrayList<Integer>();
for (int i = 0; i < 100000000; i++) {
integers.add(i);
}
}
public static void main(String[] args) {
StaticFieldMemoryLeak staticFieldMemoryLeak = new StaticFieldMemoryLeak();
staticFieldMemoryLeak.insertIntegers();
System.out.println("Done with inserting integers");
}
}
이 경우 이 목록은 사용되고 정확하게 버려지며 쓰레기 수집기는 사용한 메모리를 복구할 수 있습니다.이것은 국부 변수이기 때문에, 우리가 이 변수를 사용하지 않는 코드점에 도달했을 때,garbace 수집기는 메모리를 방출할 수 있음을 확인합니다.어떻게 예방합니까?
이제 알겠지만 정적 변수를 사용하는 것에 주의하세요.객체를 정적 선언하면 해당 라이프 사이클이 JVM의 라이프 사이클과 연관된다는 점에 유의하십시오.
2. 닫히지 않은 자원
흐름을 끄거나 연결하는 것을 잊는 것은 메모리 유출을 초래하는 흔한 문제입니다.나는 이것이 내가 실천에서 가장 많이 본 것이라고 말하고 싶다.
이 예를 보십시오.
public class UnclosedStream {
public void readFile() {
StringBuilder strBuilder = new StringBuilder();
URLConnection conn = new URL("http://testurl.com/large_file.txt").openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
while (br.readLine() != null) {
strBuilder.append(br.readLine());
}
strBuilder = null;
}
public static void main(String[] args) {
UnclosedStream unclosedStream = new UnclosedStream();
unclosedStream.readFile();
System.out.println("Done with reading file");
}
}
우리가 파일을 읽을 때 메모리 사용이 점점 증가할 것이다.그리고 BufferedReader는 영원히 닫히지 않기 때문에 파일을 읽은 후에도 메모리가 풀리지 않습니다.접속에서도 다음과 같은 상황이 발생할 수 있습니다.
public class UnclosedConnection {
public void readFile() {
URL url = new URL("ftp://fakeaddr.net");
URLConnection urlConn = url.openConnection();
InputStream inputStream = urlConn.getInputStream();
}
public static void main(String[] args) {
UnclosedConnection unclosedConnection = new UnclosedConnection();
unclosedConnection.readFile();
System.out.println("Done with connecting");
}
}
보시다시피 URLconnection은 닫히지 않았기 때문에, 열려 있는 상태를 유지하고 메모리 자원을 저장합니다.어떻게 예방합니까?
간단합니다. 항상 기억하십시오.
try (BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
// whatever else you wanna do
} catch (IOException e) {
e.printStackTrace();
}
이렇게 하면 try 문 끝에 BufferedReader가 자동으로 닫힙니다.3. 대상 인용 활동의 해시 집합과 해시 맵을 유지한다
HashSet 또는 HashMap의 중요한 특징 중 하나는 중복 요소를 피하는 것입니다.그러나 이를 실현하려면 삽입된 대상은hashCode()와 equals()가 있어야 한다.
이러한 실현 없이 대상을 삽입하면 어떤 요소가 중복되는지 판단할 수 없다.이것은 최종적으로 불필요한 대상을 많이 추가하고 메모리 유출 가능성을 높일 수 있음을 의미합니다.
어떻게 예방합니까?
해시 집중에 대상을 넣으려면hashCode () 와 equals () 를 항상 추가하십시오.
4. 문자열을 호출합니다.큰 문자열의 인터넷 () (자바 8 이전)
밧줄.방법은 메모리에 문자열 대상의 정확한 복사본을 만들고 문자열 상수 탱크에 저장합니다.마찬가지로 JVM 메모리에 저장되어 있기 때문에 수집할 수 없기 때문에 스팸 수집기가 충분한 메모리를 방출하지 못할 수도 있다.
JVM 메모리에 대용량 문자열을 저장해야 하는 경우 PermGen 공간을 늘리는 것을 고려하십시오.
Java8에서 PermGen space is replaced by Metaspace OutOfMemory 오류는 발생하지 않습니다.
응용 프로그램에서 가능한 메모리 유출을 어떻게 찾습니까
알겠습니다. 만약 응용 프로그램을 처리하고 있다면, 메모리 유출이 의심됩니다.어떻게 알았어요?
1.일식
이것은 모든 JDK 1.5+ 호환 코드에 적용됩니다.Eclipse는 일부 메모리 누수를 경고합니다.Closeable을 실행하는 객체가 있고 참조가 제거되었지만 객체가 닫히지 않으면 경고가 표시됩니다.
이 기능을 활성화하려면 Eclipse 기본 설정으로 이동하여 다음을 설정합니다.
2. 지루한 쓰레기 수집
응용 프로그램 JVM에서 구성한 -verbose:gc 매개 변수를 활성화하여 이 작업을 수행할 수 있습니다.이것은 쓰레기 수집에 대해 매우 상세한 추적을 허용할 것이다.
3. 기준 테스트
기준 테스트는 코드 부분의 성능을 측정할 수 있습니다.이렇게 하면 너는 끊임없이 그것을 감시하여 어떤 특정한 방법이 매우 느리는지 볼 수 있다.Java 벤치마크 테스트에 대한 자세한 정보follow this link를 원하는 경우
4. 분석
Java 탐색기는 JVM급 작업(스팸 수집 포함)을 모니터링하는 도구입니다.일부 유행은 YourKit 및 VisualVM입니다.
5. 코드 검토
이것은 보통 좋은 실천이지만, 만약 메모리 유출을 발견하려고 한다면, 코드를 자세히 검사하고, 다른 그룹으로 하여금 그것을 검사하게 하세요.너는 내가 여기서 제기한 몇 가지 문제에 주의할 수 있을 것이다.
나는 이것이 네가 메모리 유출을 더 많이 이해하고 그것을 어떻게 피하는지 도울 수 있기를 바란다.만약 당신이 지금 그 중 하나를 찾으려고 노력하고 있다면, 행운을 빕니다.
Reference
이 문제에 관하여(Java 메모리 누수를 방지하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ca5th/memory-leaks-in-java-and-how-to-avoid-them-48h3텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)