플레이어의 키보드 입력(8종류)이 달라질 때마다
크기가 8인 배열 하나에 저장한 다음에
이 배열들을 쭉 모아놓은 자료형을 만들어서
추후에 플레이어의 입력 기록을 볼 수 있게 만들려고 했어요
처음에는 모아 놓는 자료형을 구현하는데 List를 사용했어요
새로운 입력이 들어올 때마다 list.Add(~)를 사용해서
키보드값 배열을 저장했습니다
근데 문제점이 하나 생긴거에요
list.Add()는 구조적 특성상 호출될때마다
배열을 새로 생성하고 할당하고를 반복해서
가비지를 많이 생성해버리는거죠
덕분에 키보드 입력이 와다다 엄청 많이 들어오게 되면
끔찍할 정도의 렉과 스파이크가 발생했어요...
이를 해결하고자 자료형을 LinkedList로 리팩토링했어요
LinkedList.AddLast(~)를 사용하면
노드 하나를 생성하는데에 메모리 할당이 들어갈 뿐
가비지가 많이 발생하지 않아서 부하가 적게 들어가게 되었어요
이제 키보드를 와다다 입력해도 더이상 렉이 발생하지 않더라고요
물론 이제 인덱스는 사용하지 못하니
노드들 사이를 왔다갔다 하는 불편함은 있겠다만...
오늘 개발한 것 중에서 제일 뿌듯하게 만든거라 한번 올려봤어요
역시 자료구조를 배우길 잘했어
미친 족고수
음.. 질문이 있슴다 저도 선입력 시스템 땜에 큐를 쓰지만 키보드 왕창 누른다고 렉이 걸리지는 않던데.. 링크드리스트라 키입력이 많이 쌓이면 쌓일 수록 처리 시간이 왕창 늘어나는 건가요??
구조체 + 정적 배열을 쓰는 게 낫지 않나 싶은데.. 아니면 ㅈㅅ
제가 구현하던걸 좀더 구체적으로 말하면 키를 입력하면 같은 시간 내에 입력했던 키 정보(keyDown, keyUp,keyPressed 등)를 모아가지고서 일종의 키보드 대본?을 만들려고 했습니다. 이 대본을 따라쟁이 캐릭터에게 넣어가지고서 플레이어의 입력을 언제든 따라할 수 있도록 만들려고요. 그래서 어쩔 수 없이 어느정도 왕창 쌓이게 될 수 밖에 없긴 해요... 다만 그 쌓는 과정에서 엄청난 렉이 걸려서 자료구조를 바꾼거고요. 제가 기획한 걸 구현하려면 계속 List를 쓰든 LinkedList를 쓰든간에 차피 나중에 처리할 자료 양은 똑같이 많을거에요... ㅠㅠ
array 쓰면 입력값이 계속 늘어나게 되면 array 길이를 계속 바꿔줘야 하지 않나요?? 그리고 얼만큼 늘려야 하는지도 플레이어의 플레이 스타일에 따라서 딱 정하기 힘들거 같아서... 혹시 어떻게 구현하려고 하셨는지 여쭤봐도 될까요??
엇 저도 초짜라 이상한 소리하는 것 같아서 지웠는데.. 최초 사이즈를 한 5000쯤 두고 꽉차면 그때 5000씩 늘리면 되지 않을까 했어요 이러면 요소 추가할 때마다 파편화도 안 생기고.. GC도 뭐 배열 크기 늘릴 때만 염두하면 될 거라 생각했음
아하 아예 크게 잡고 사용하려고 하셨군요. 사실 가장 간단한 해법이긴 하죠 ㅋㅋㅋ 근데 저는 메모리는 필요한 만큼만 사용하고 싶어서 크게 할당하는건 한번 지양해보고 싶었어요. 혹시라도 지금 방식을 쓰다가 성능에 문제가 생기면 님이 알려주신 방법을 사용해볼께요. 아이디어 감사합니다!!
8종류 입력을 순서 상관없이 특정 순간에 캡쳐하는 거면 비트 플래그 쓰면 틱당 1바이트로도 될 듯
헉 그건 생각치 못한 방법이네요!! 제가 각 입력당 4가지 입력을 측정받으니까(pressed, notpressed, up, down) 이론상으로 8×4=32비트, 4바이트로 8개 입력 상태를 동시에 표현할 수 있겠어요 ㄷㄷ 생각치도 못한 방식인데 이거는 메모리 최적화 할 때 써봐야겠어요. 진짜 감사합니다!!
웬만한 경우 리스트 용량 어느정도 주고 신경 끄는 게 좋음 극한의 최적화가 필요하면 버퍼 쓰는 게 맞기는 한데 이렇게 까지 할 거면 힙에서 대강 고정 크기 잡고 하는 게 아니라 별도의 쓰레드나 코루틴에서 Span 구조체 배열로 스택 메모리에 고정 크기 잡아놓고 입력 버퍼로 쓰다가 적당한 시점에 힙쪽 컬렉션으로 옮기는 정도는 해야 의미가 있을 듯
지금 보니까 댓 위치를 잘못 달았네 다른 댓 버퍼 얘기에 이어서 보면 됨
한 번에 100번 입력했냐 10번입력했냐 이런 체크가 필요한 것이 아니라면 필요한 크기만큼의 배열 선언해두고 입력 들어올 때마다 or 일정 타이밍마다 인덱스 증가시켜가면서 현재 입력값을 현재 인덱스에 넣어주고 인덱스 증가 및 나머지 연산으로 배열 순회하도록 해주면 입력 버퍼를 만들 수 있을 것 같아요. + 몇 번째 이전 입력값 체크도 순차순회할 필요 없어짐 그렇지만 저도 링크드리스트 좋아함.
위에 분도 말씀해주신거 같은데 확실히 버퍼를 만들어서 쓰는게 최적화 측면에는 좋은가 보긴 한가 보네요. 원래 배열을 처음부터 크게 잡는거를 좋아하진 않았는데 생각이 조금씩 바뀌네요. 조언 감사드립니다!
타자가 한 백만타 되나봄
아무래도 나중에 hdd에 쓰거나 네트워크로 보낼꺼 생각하면 버퍼를 쓰는게 편하긴 하니 사람들이 추천하는듯... 글쓴이 상황이야 잘 모르겠지만 나라면 대충 5000사이즈 버퍼 2개 만들어서 하나는 쓰고 꽉차면 다른 하나로 넘어가는 동안 다른 한 스레드에서 그걸 하드에쓰든 네트워크로 보내고 다시 비우고 이런식으로 반복할듯? 계속 메모리에 들고있어야된다면 말한대로 링크드리스트로 하되 각 리스트의 노드가 청크여서 n개의 데이터를 포함하는것도 좋겠지
제 경우에는 플레이어가 한 맵에 들어갈 때부터 입력값 녹화를 시작하고 나가면 녹화를 끝내거든요. 근데 맵을 들어가고 나가고 하는게 매우 자유로워서 어떤 플레이어는 5초만에 나갈 수도 있고 어떤 플레이어는 40분 만에 나갈 수도 있고 해서요...(얼만큼 저장하게 될지가 감이 안잡혀서...)그 시간동안 플레이어의 입력을 어느정도 지속적으로 받아서 저장해놔야 하는데 배열+버퍼를 쓰는거랑 링크드 리스트를 쓰는거랑 어느게 더 나을거 같으세요??
참고로 리스트는 add 할떄마다 재할당이아니라 최대용량 넘어갈떄만 곱하기 2로 재할당함 중간삽입아니고 단순 add로 렉걸리는거면 다른문제일 가능성이클꺼임 ㅇㅇ
아 그러면 렉걸리는 이유를 살짝 알겠네요... 제가 여태까지 List를 초기 크기 할당을 안하고 썼거든요;;(List<>(32) 이렇게 안씀;; 크기 설정할 수 있는지도 몰랐네요) 그래서 입력값 테스트를 하면 평균적으로 30~60개 정도를 테스트 했는데 입력값 1~16개 구간에서 배열 크기가 뿅뿅뿅 늘어나고 재할당 되서 렉걸렸나봐요... 입력값이 64개가 넘어간 이후로는 렉걸리는지 확인해볼걸 그랬네요
Linkedlist의 이점은 리스트 중간에 노드를 삽입/삭제 시 오버헤드가 적은 것입니다요... Push만 한다면 동적배열이 더 좋을 것 같사와요... - dc App
음 너무 잘못된 방식으로 List를 쓰고, 잘못알고계시네 LinkedList는 노드 할당 비용이 들어감 List<>내부는 배열기반이라서 오버헤드가 매우 적고 실행속도가 가장빠름 배열요소의 자료 크기가 너무 커서 배열 재할당 비용이 크거나 끝에 추가가 아니라 중간추가가 많을때만 LinkedList가 유리하고 그외의 경우(끝에추가하는 대부분의경우)엔 모두 List가 성능상으로 유리함
그럼 인붕이의 경우 왜 LinkedList가 빠른거처럼 느껴졋냐면 List의 초기 Capacity를 설정해주지않아서 그럼 LinkedList는 결국 최종적으로 그걸 사용할때도 (순차접근 등) List보다 훨씬 느림 그리고 추가할때도 Capacity를 설정한 List보다 훨씬 느릴수밖에없음 메모리 오버헤드도 많고 캐시효율도 List보다 뒤떨어지거든 만약 List의 Capacity 초기용량을 넉넉히 잡더라도 너무빠른 속도로 초기 용량이 넘어 재할당될거같다면 LinkedList가 아니라 배열풀링을 하는게 옳은 선택임.
맞아요 사실 이 모든 질문의 원인은 List<>가 초기 배열 크기 선언을 할 수 있는지를 몰랐어서 그래요... 진작 알았다면 List<>를 계속 썼겠지만 일단 지금은 잘 작동하니까 나중에 문제 생기면 리팩토링을 다시 해볼께요. 자료구조적인 얘기랑 팁도 감사합니다~~