루비 앱의 스택 크기를 늘리는 방법. 재귀 앱 Geting : 스택 레벨이 너무 깊습니다 (SystemStackError)

StackOverflow https://stackoverflow.com/questions/242617

  •  04-07-2019
  •  | 
  •  

문제

stackoverflow.com에 스택 오버 플로우 질문 게시, 얼마나 재미있는 지 :-)

재귀적인 루비 코드를 실행하고 다음을 얻습니다. "Stack level too deep (SystemStackError)"

(나는 코드가 작동한다고 확신합니다. 나는 무한 재귀 사망의 나선에 있지 않지만 어쨌든 요점은 아닙니다)

어쨌든 내 루비 앱의 허용 스택 깊이/크기를 변경할 수 있습니까?

오류가 "스택 레벨"이라고 말하기 때문에 이것이 루비의 제한이라면 그것을 얻지 못합니다. 루비가 어떻게 든 스택의 '레벨'을 계산한다는 인상을 주거나 단순히 스택이 가득 차 있다는 것을 의미한다면.

Vista와 Ubuntu에서 동일한 결과 로이 프로그램을 실행하려고 시도했습니다. Ubuntu에서 나는 'Ulimit -s'로 스택 크기를 8192에서 16000으로 변경하려고 시도했지만 아무것도 바꾸지 않았습니다.

편집 : 피드백에 감사드립니다.
재귀 기능을 사용하는 것이 아마도 가장 강력한 방법이 아님을 알고 있습니다. 그러나 그것은 요점도 아닙니다. 스택 크기를 늘리는 방법이 있는지 궁금합니다. 기간. 그리고 내가 언급했듯이 루비 스크립트를 실행하기 전에 Ulimit -S 16000을 실행하려고했습니다. 개선없이 .. 내가 잘못 사용하고 있습니까?

EDIT2 : 실제로 코드의 가장자리 사례에서 무한 재귀를 가지고있었습니다.
당신이 얻을 때 잘린 루비 스택 추적 "Stack level too deep" 오류는 약간 오해의 소지가 있습니다.
여러 기능과 관련된 재귀 행동을 할 때는 재귀 횟수가 실제로보다 훨씬 낮다는 인상을받습니다. 이 예에서는 190 건을 넘지 않아 충돌 할 수 있지만 실제로는 약 15000 통화입니다.

tst.rb:8:in `p': stack level too deep (SystemStackError)
        from tst.rb:8:in `bar'
        from tst.rb:12:in `bar'
        from tst.rb:19:in `foo'
        from tst.rb:10:in `bar'
        from tst.rb:19:in `foo'
        from tst.rb:10:in `bar'
        from tst.rb:19:in `foo'
        from tst.rb:10:in `bar'
         ... 190 levels...
        from tst.rb:19:in `foo'
        from tst.rb:10:in `bar'
        from tst.rb:19:in `foo'
        from tst.rb:22

-안드레스

도움이 되었습니까?

해결책

Ruby는 C 스택을 사용하므로 옵션에는 일부 컴파일러/링커 스택 크기 플래그와 함께 Ulimit 사용 또는 Ruby를 컴파일하는 것이 포함됩니다. 꼬리 재귀는 아직 구현되지 않았으며 Ruby의 현재 재귀에 대한 지원은 그리 좋지 않습니다. 시원하고 우아한 재귀는 언어의 한계에 대처하고 다른 방식으로 코드를 작성하는 것을 고려할 수 있습니다.

다른 팁

이 질문과 그 대답은 C 스택을 사용한 루비 1.8.x로 거슬러 올라갑니다. 루비 1.9.x는 나중에 자체 스택이있는 VM을 사용합니다. Ruby 2.0.0 이상에서 VM 스택의 크기는 RUBY_THREAD_VM_STACK_SIZE 환경 변수.

당신이 무한 재귀 상황이 없다고 확신한다면, 당신의 AlgoryThm은 Ruby가 그것을 재구성하는 방식으로 실행하는 데 적합하지 않습니다. AlgoryThM을 재귀에서 다른 종류의 스택으로 변환하는 것은 매우 쉽고 시도해 볼 것을 제안합니다. 다음은 할 수있는 방법입니다.

def recursive(params)
  if some_conditions(params)
     recursive(update_params(params))
  end
end

recursive(starting_params)

로 변모합니다

stack = [starting_params]
while !stack.empty?
  current_params = stack.delete_at(0)
  if some_conditions(current_params)
    stack << update_params(current_params)
  end
end

유키히로 마츠모토는 썼다 여기

Ruby는 C 스택을 사용하므로 Ulimit을 사용하여 스택 깊이에 제한을 지정해야합니다.

코드에서 무슨 일이 일어나고 있는지 생각해보십시오. 다른 포스터에서 언급했듯이 통역사의 C 코드를 해킹 할 수 있습니다. 하지만. 결과는 더 많은 RAM을 사용하고 있으며 스택을 다시 불지 않을 것이라는 보장이 없다는 것입니다.

정말 좋은 솔루션은 당신이하려는 일에 대한 반복 알고리즘을 제시하는 것입니다. 때로는 사고가 도움이 될 수 있으며 때로는 스택에 밀어 넣는 물건을 사용하지 않는 경우가 있습니다.이 경우 재귀 통화를 변이 상태로 바꿀 수 있습니다.

이런 종류의 물건을 처음 접한다면 SICP를 살펴보십시오. 여기 몇 가지 아이디어를 위해 ...

동일한 문제가 있었고 Linux 또는 Mac에서는 쉽게 수정하기가 매우 쉽습니다. 다른 답변에서 말했듯이 루비는 시스템 스택 설정을 사용합니다. 스택 크기를 설정하여 Mac 및 Linux에서 쉽게 변경할 수 있습니다. Fox example:

ulimit -s 20000

현재 루비 1.9.2 다음과 같은 것로 테일 컬 최적화를 켤 수 있습니다.

RubyVM::InstructionSequence.compile_option = {
  tailcall_optimization: true,
  trace_instruction: false
}

RubyVM::InstructionSequence.new(<<-EOF).eval
  def me_myself_and_i
    me_myself_and_i
  end
EOF
me_myself_and_i # Infinite loop, not stack overflow

그것은 피할 것입니다 SystemStackError 오류 재귀 호출이 메소드의 끝에 있고 방법 만. 물론이 예제는 대신 무한 루프를 초래할 것입니다. 깊은 재귀 후에 가기 전에 얕은 재귀 (및 최적화 없음)를 사용하여 디버깅하는 것이 가장 좋습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top