실제로 스택 오버플로 오류를 일으키는 요소는?
사방을 다 찾아봤는데 확실한 답을 찾을 수가 없다.설명서에 따르면 자바는 자바.랑(java.lang)을 던진다.다음 상황에서 StackOverflowError 오류 발생:
응용 프로그램이 너무 깊이 반복되어 스택 오버플로가 발생할 때 발생.
그러나 이것은 두 가지 의문을 제기한다.
- 재귀뿐만 아니라 스택 오버플로가 발생하는 다른 방법은 없을까?
- StackOverflowError는 JVM이 실제로 스택을 오버플로하기 전에 발생하는가, 아니면 이후에 발생하는가?
두 번째 질문에 대해 자세히 설명하려면:
Java가 StackOverflowError를 발생시킬 때 스택이 힙에 기록되지 않았다고 안전하게 가정할 수 있는가?스택 오버플로를 발생시키는 함수의 try/catch에서 스택 또는 힙 크기를 축소하는 경우 작업을 계속할 수 있는가?문서화된 곳이 있나?
내가 찾고 있지 않은 답변:
- StackOverflow는 잘못된 반복으로 인해 발생한다.
- 스택 오버플로우는 힙이 스택과 만날 때 발생한다.
스택 오버플로 오류는 버퍼에 할당되지 않은 메모리에 기록하여 일부 다른 메모리 위치를 손상시킬 위험이 있을 때 네이티브 프로그램에서 버퍼 오버플로 예외와 같다고 생각하는 것 같다.전혀 그렇지 않다.
JVM에는 각 스레드의 각 스택에 대해 지정된 메모리가 할당되어 있으며, 이 메모리를 채우기 위해 메서드를 호출하려고 하면 JVM이 오류를 발생시킨다.길이가 N인 색인 N에서 쓰려고 할 때처럼. 어떤 메모리 손상도 일어날 수 없다.스택은 힙에 쓸 수 없다.
StackOverflowError는 스택에 대한 OutOfMemoryError로, 단순히 사용 가능한 메모리가 더 이상 없다는 신호를 보낸다.
가상 시스템 오류의 설명(제6.3조)
StackOverflowError:일반적으로 실행 프로그램의 오류로 인해 스레드가 제한되지 않은 수의 재귀 호출 작업을 수행하고 있기 때문에 Java Virtual Machine 구현에 스레드의 스택 공간이 부족하게 되었다.
재귀뿐만 아니라 스택 오버플로가 발생하는 다른 방법은 없을까?
물론이지. 다시는 돌아오지 말고 계속 전화해라.하지만 재귀가 허락되지 않는 한 많은 방법이 필요할 것이다.사실, 그것은 차이를 만들지 않는다: 스택 프레임은 스택 프레임이다. 그것이 재귀적 방법의 하나인지 아닌지는 같다.
두 번째 질문에 대한 답은 다음과 같다.JVM이 다음 호출에 대해 스택 프레임을 할당하려고 하면 스택 오버플로우가 감지되며, 불가능함을 발견하게 된다.그래서 아무것도 덮어쓰지 않을 것이다.
재귀뿐만 아니라 스택 오버플로가 발생하는 다른 방법은 없을까?
챌지 수지 수지 )StackOverflowError
재귀 없이(실패, 주석 참조):
public class Test
{
final static int CALLS = 710;
public static void main(String[] args)
{
final Functor[] functors = new Functor[CALLS];
for (int i = 0; i < CALLS; i++)
{
final int finalInt = i;
functors[i] = new Functor()
{
@Override
public void fun()
{
System.out.print(finalInt + " ");
if (finalInt != CALLS - 1)
{
functors[finalInt + 1].fun();
}
}
};
}
// Let's get ready to ruuuuuuumble!
functors[0].fun(); // Sorry, couldn't resist to not comment in such moment.
}
interface Functor
{
void fun();
}
}
표준으로 컴파일javac Test.java
을 가지고 달리다java -Xss104k Test 2> out
그 후엔more out
다음과 같이 말할 것이다.
Exception in thread "main" java.lang.StackOverflowError
두 번째 시도.
이제 그 생각은 더욱 간단해졌다.Java의 원시형은 스택에 저장될 수 있다.그러니까 복식 선언을 많이 하자, 예를 들면.double a1,a2,a3...
이 스크립트는 다음을 위해 코드를 작성, 컴파일 및 실행할 수 있다.
#!/bin/sh
VARIABLES=4000
NAME=Test
FILE=$NAME.java
SOURCE="public class $NAME{public static void main(String[] args){double "
for i in $(seq 1 $VARIABLES);
do
SOURCE=$SOURCE"a$i,"
done
SOURCE=$SOURCE"b=0;System.out.println(b);}}"
echo $SOURCE > $FILE
javac $FILE
java -Xss104k $NAME
그리고... 예상치 못한 일이 생겼어
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f4822f9d501, pid=4988, tid=139947823249152
#
# JRE version: 6.0_27-b27
# Java VM: OpenJDK 64-Bit Server VM (20.0-b12 mixed mode linux-amd64 compressed oops)
# Derivative: IcedTea6 1.12.6
# Distribution: Ubuntu 10.04.1 LTS, package 6b27-1.12.6-1ubuntu0.10.04.2
# Problematic frame:
# V [libjvm.so+0x4ce501] JavaThread::last_frame()+0xa1
#
# An error report file with more information is saved as:
# /home/adam/Desktop/test/hs_err_pid4988.log
#
# If you would like to submit a bug report, please include
# instructions how to reproduce the bug and visit:
# https://bugs.launchpad.net/ubuntu/+source/openjdk-6/
#
Aborted
100% 반복하는 겁니다.이는 두 번째 질문과 관련이 있다.
StackOverflowError는 JVM이 실제로 스택을 오버플로하기 전에 발생하는가, 아니면 이후에 발생하는가?
따라서 OpenJDK 20.0-b12의 경우 JVM이 먼저 폭발했다는 것을 알 수 있다.하지만 벌레 같은데, 누군가 댓글로 확인해 줄 수 있을 것 같아, 확실하지 않아.이거 신고할까?어쩌면 이미 새로운 버전으로 고쳐졌는지도 몰라...JVM 사양 링크에 따라(코멘트에서 JB Nizet이 제공) JVM은 다음을 수행해야 한다.StackOverflowError
, 죽지 않음:
스레드의 계산에 허용된 것보다 더 큰 Java Virtual Machine 스택이 필요한 경우 Java Virtual Machine은 StackOverflowError를 발생시킨다.
세 번째 시도.
public class Test {
Test test = new Test();
public static void main(String[] args) {
new Test();
}
}
우리는 새로운 것을 창조하기를 원한다.Test
것이다그래서, 그것의 (불가결한) 건설자가 불려질 것이다.그런데 그 직전에 멤버들 다.Test
초기화되다그렇게Test test = new Test()
먼저 실행된다...
우리는 새로운 것을 창조하기를 원한다.Test
목적어...
업데이트: 운이 나빴군, 이건 재귀야. 난 여기서 그것에 대해 질문을 했어.
"StackOverFlowException"은 없다.당신이 의미하는 것은 "StackOverFlowError"이다.
그래, 그렇게 하면 스택이 지워지기 때문에 잡으면 일을 계속할 수 있지만, 그건 나쁘고 추한 선택일 거야.
정확히 오류가 발생했을 때? - 메서드를 호출하고 JVM이 메모리가 충분한지 확인할 때.물론, 만약 그것이 가능하지 않다면, 에러는 던져진다.
- 아니, 그렇게 해야만 그 오류를 얻을 수 있어: 네 스택을 가득 채우는 거야.그러나 재귀만을 통해서도, 다른 방법을 무한히 부르는 방법을 호출하는 것이 아니다.그것은 매우 구체적인 오류라서 아니다.
- 스택이 가득 차기 전에, 정확히 검증할 때 던져진다.사용 가능한 공간이 없다면 데이터를 어디에 두시겠습니까?다른 사람을 무시하는 거야?
StackOverFlowError의 가장 일반적인 원인은 지나치게 깊이 또는 무한 반복이다.
예를 들어,
public int yourMethod(){
yourMethod();//infinite recursion
}
Java의 경우:
있다two
더미와 스택을 메모리에 있는 영역.그stack memory
로컬 변수와 함수 호출을 저장하는 데 사용되는 동안heap memory
Java에 객체를 저장하는 데 사용된다.
함수 호출이나 로컬 변수를 저장하기 위해 스택에 메모리가 남아 있지 않으면 JVM이 이를 던진다.java.lang.StackOverFlowError
객체를 생성하기 위한 힙 공간이 더 이상 없을 경우 JVM은java.lang.OutOfMemoryError
자바에 물건을 보관할 수 있는 장소는 크게 두 군데다.첫 번째는 동적으로 할당된 개체에 사용되는 힙입니다. new
.
또한 실행 중인 각 스레드는 자체 스택을 가지며, 그 스택에 할당된 메모리 양을 얻는다.
메서드를 호출하면 데이터가 스택에 푸시되어 메서드 호출, 전달되는 매개 변수 및 할당되는 로컬 변수를 기록한다.5개의 로컬 변수와 3개의 매개변수를 가진 방법은 a보다 더 많은 스택 공간을 사용한다.void doStuff()
국소 변수가 없는 방법
스택의 주요 장점은 메모리 조각화가 없고, 하나의 메서드 호출에 대한 모든 것이 스택 상단에 할당되며, 메서드에서 돌아오는 것이 쉽다는 것이다.메서드에서 다시 스택을 이전 메서드로 되돌리려면 반환 값에 필요한 값을 설정하십시오.
스택은 스레드당 고정 크기이기 때문에(Java Spec은 고정 크기를 필요로 하지 않지만, 작성 시 대부분의 JVM 구현은 고정 크기를 사용한다는 점에 유의하십시오) 그리고 바라건대 메서드를 호출할 때마다 스택의 공간이 필요하기 때문에 이제 스택이 고갈될 수 있는 이유와 고갈될 수 있는 원인이 무엇인지 명확해야 한다.정해진 수의 메서드 호출도 없고, 재귀에 대해 특별한 것도 없으며, 메서드라고 부르려고 하는 예외도 있고, 메모리가 충분하지 않다.
물론 스택의 크기는 일반 코드에서 일어날 가능성이 매우 낮을 정도로 높게 설정되어 있다.재귀적 코드에서는 매우 쉽게 다시 깊이로 되돌릴 수 있으며, 그 시점에서 당신은 이 오류에 부딪히기 시작한다.
StackOverflowError
응용 프로그램이 너무 깊이 반복되기 때문에 발생(이것은 예상한 대답이 아니다).
이제 또 다른 일이 일어날 것이다.StackOverflowError
방법을 찾을 때까지 계속 호출하는 거야StackOverflowError
, 그러나 아무도 프로그램할 수 없다.StackOverflowError
그리고 비록 프로그래머들이 그렇게 한다고 하더라도, 그들은 모든 프로그래머들이 프로그래밍하는 동안 이해해야 하는 사이클로매틱 컴플라이언스에 대한 코딩 표준을 따르지 않는다.이러한 'StackOverflowError'의 이유는 이를 수정하는 데 많은 시간이 필요할 것이다.
그러나 자신도 모르게 한두 줄의 코딩이 원인이 된다.StackOverflowError
이해할 수 있고 JVM이 그걸 던지면 즉시 고칠 수 있어여기 다른 질문들에 대한 그림이 있는 내 답안이 있다.
StackOverflow는 함수 호출이 이루어지고 스택이 가득 찰 때 발생한다.
ArrayOutOfBoundException처럼.그것은 어떤 것도 부패시킬 수 없다. 사실 그것을 잡고 회복하는 것은 매우 가능하다.
보통 통제되지 않은 재귀의 결과로 발생하지만, 기능 호출의 매우 깊은 스택에 의해서도 발생할 수 있다.
c#에서는 객체 특성을 잘못 정의함으로써 다른 방식으로 스택 오버플로를 달성할 수 있다.예:
private double hours;
public double Hours
{
get { return Hours; }
set { Hours = value; }
}
보시다시피, 이것은 대문자 H로 영원히 Hours를 반환하고, 그 자체로 Hours 등을 반환할 것이다.
스택 오버플로는 메모리가 부족하거나 언어 관리자(CLR, JRE)가 코드가 무한 루프에 걸린 것을 감지하기 때문에 관리되는 언어를 사용할 때 종종 발생한다.
그러나 이것은 두 가지 의문을 제기한다.
- 재귀뿐만 아니라 스택 오버플로가 발생하는 다른 방법은 없을까?
- StackOverflowError는 JVM이 실제로 스택을 오버플로하기 전에 발생하는가, 아니면 이후에 발생하는가?
또한 스택의 한계보다 큰 크기를 할당할 때도 발생할 수 있다(예:
int x[10000000];
).두번째 답은
각 스레드는 해당 스레드에서 실행되는 각 방법에 대한 프레임을 고정하는 자체 스택을 가지고 있다.그래서 현재 실행 방법은 스택의 맨 위에 있다.모든 방법 호출에 대해 새로운 프레임이 생성되어 스택의 맨 위에 추가(푸시)된다.메서드가 정상적으로 반환되거나 메서드를 호출하는 동안 검색되지 않은 예외가 발생할 경우 프레임을 제거(도핑)한다.스택은 푸시 프레임 객체와 팝 프레임 객체를 제외하고 직접 조작되지 않으므로 프레임 객체는 힙에 할당될 수 있으며 메모리는 연속적일 필요가 없다.
그래서 우리는 스레드에 쌓이는 것을 고려함으로써 결론을 내릴 수 있다.
스택은 동적 또는 고정된 크기일 수 있다.스레드에 허용되는 것보다 큰 스택이 필요한 경우StackOverflowError
던져지다스레드에 새 프레임이 필요하고 이를 할당할 메모리가 충분하지 않은 경우OutOfMemoryError
던져지다
여기서 JVM에 대한 설명을 볼 수 있다.
참조URL: https://stackoverflow.com/questions/22182669/what-actually-causes-a-stack-overflow-error
'programing' 카테고리의 다른 글
다중 라인 전처리기 매크로 (0) | 2022.04.24 |
---|---|
gdb 명령 화면이 얼마나 선명하십니까? (0) | 2022.04.24 |
Excel 셀의 숫자 문자열을 숫자가 아닌 문자열로 읽으려면 어떻게 해야 하는가? (0) | 2022.04.24 |
문자 배열이 비어 있는지 확인하는 가장 좋은 방법 (0) | 2022.04.24 |
vue 관련 문제 다시 한 번 발생: vue를 2.5에서 2.6.8로 업데이트하고 [Vue warn]:구성 요소를 마운트하지 못함: 템플릿 또는 렌더 함수가 정의되지 않음 (0) | 2022.04.24 |