2013-07-16 5 views
0

저는 그래픽 스레드를 업데이트해야하는 다른 스레드가있는 쓰고있는 게임에 libgdx을 사용하고 있습니다. libgdx가 의도적으로 스레드로부터 안전하지 않고 다른 스레드가 그래픽 스레드의 변수를 직접 수정하도록 허용했기 때문에 충돌이 발생했습니다.클로저를 포함한 Runnable을 재사용 할 수 있습니까?

libgdx docs에는 다음 코드와 비슷한 것이 좋습니다. 이것은 기본적으로 들어오는 정보를 포함하는 클로저이며, 그래픽 스레드가 도착할 때 처리됩니다.

가비지 수집을 피하기 위해 리스너 외부에서 실행 파일을 선언하도록 수정했습니다.하지만 이전에 실행 가능 파일을 덮어 쓸 수있는 위치에서 경쟁 조건을 만들었습니다. 그래픽 스레드는 이전 정보를 소비합니까?

지금까지 다른 곳에서는 가비지 수집을 피할 수 있었고, 게임에서 안드로이드의 낮은 대기 시간 오디오 바인딩을 활용하기 때문에 가비지 수집이 정말 적군입니다.

제안 사항?

private Runnable runnable; 
private SomeListener listener = new SomeListener() { 
    @Override 
    public void messageIn(final String source, final String s, final Object... l) { 
     runnable = new Runnable() { 
      @Override 
      public void run() { getWorkspace().messageIn(s,l); } 
     }; 
     Gdx.app.postRunnable(runnable); 
    } 

}};

답변

1

나는 가비지 컬렉션을 피할 수있는 희망의 리스너의 실행 가능한 외부 선언을 수정했습니다,하지만 지금은 경쟁 조건을 생성 한 실행 가능한 전에 덮어 쓸 수있는 곳 나에게 발생 이전 정보를 소비하는 그래픽 스레드에?

네, 그렇습니다. 또한 ThreadLocal은 콜백을 실행하는 스레드와 실행 가능한 스레드를 처리하는 스레드가 다르기 때문에 사용할 수 없습니다.

Runnable 클래스의 BlockingQueue을 만들면됩니다. 실행 방법이 끝나면 RunnableBlockingQueue 끝 부분에 재사용 할 수 있습니다. messageIn(...) 메서드가 호출 될 때 queue.poll()을 호출하고 큐에 아무 것도없는 경우에만 새 메서드를 만듭니다. 이렇게하면 메모리 동기화는 증가하지만 GC 대역폭은 낮아집니다. 그것은 당신을 많이 얻지 못할 수도 있습니다.

메모리 프로파일 러를 실행하여 리팩토링에 집중하여 메모리 사용을 줄이는 것이 좋습니다.

+0

내 메시지가 작습니다 float 또는 two)를 사용하므로 좋은 옵션이 될 수 있습니다. 메모리 동기화 비용이 메시지 크기에 비례한다고 가정합니다. 그리고 .. 오 .. 만약 내가 새로운 Runnable에 없다면 어떻게하면 내 클로저가 작동 할까? –

+0

동기화 비용은 아마도 선형 비용 일 수 있습니다. @DarenSchwenke 메시지의 크기를 고려하지 않았습니다. 폐쇄 장소는 어디입니까? 익명의 클래스이지만 클로저가 표시되지 않습니다. – Gray

+0

getWorkspace()를 통해 실행 가능한 실행 호출 내에서 messageIn의 s 및 l을 사용합니다. messageIn (s, l); 아마도 혼란스러워 할 것입니다. 외부 messageIn은 다른 스레드의 메소드이고 내부는 그래픽 스레드의 메소드입니다. 새로운 Runnable 권한의 선언에 사용될 때 바깥 쪽에서 최종적으로 클로저가 생성됩니다 ... 아니면 실수입니다. (약 6 개월 전에 자바를 시작한 펄 녀석) –

1

게임을 개발 중이므로 모든 메시지를 대기열에 게시하고 필요에 따라 게임 루프에서 소모하십시오.

+0

맞지만 나중에 내용을 가비지 수집하지 않고 메시지를 작성하려면 어떻게해야합니까? messageIn 내에서 실행 가능한 선언을하면 사용자가 제안한 것을 성취하지만 가비지 콜렉션이 발생합니다. –

+0

참조가 대기열에있는 동안 수집되지 않습니다. 대기열에서 그것을 제거하고 소모하며 GC는 그 이후에 ref를 제거 할 수 있습니다. –

+0

나는 여기서 GC를 피하려고 노력하고있다. 이 방법을 사용하는 현재의 GC는 매 30 초마다 2-5ms입니다. 그러나 지연 시간이 짧은 오디오 요구 사항으로 인해 총 사용 가능 시간이 6ms 밖에되지 않습니다. 너무 많습니다. postRunnable()은 그래픽 스레드에 대한 변경 사항을 올바르게 반영하는 데 사용할 수있는 메서드이므로 질문을 설정하면 GC없이 해당 Runnable을 설정하고 해제 할 수 있습니다. 실제로 GC를 가질 여유가있는 유일한 시간은 화면 변경 또는 사용자가 오디오 입/출력을 일시 중지하는 동안입니다.이 일을 만드는 나의 단순한 방법은 그때까지 모든 것을 풀링하고 다시 사용하는 것입니다. –

관련 문제