Binary String 과 Bit Mask 성능 비교

Engineering

개요

1 Word 영역을 16 bit 로 해석 인터페이스 예시

자동화 프로그램에서는 설비의 메모리를 읽고 상태를 해석하는 작업이 거의 필수적으로 발생합니다.

특히 자주 접하게 되는 형태중 하나가 1 Word(2 Byte, 16 Bit)에 여러 상태 정보를 Bit 단위로 의미를 가지는 형식입니다. 솔직히 편의성으로만 보면 1 Word 단위로 의미를 부여하는게 제일 편하지만 메모리 낭비가 심합니다.

대표적으로 PLC 같은경우 알람여부, 센서 On/Off 상태를 표기할때 많이 사용합니다.

어떤 방식으로 해석할까?

여러가지 방법이 있지만 저는 2가지 방식을 많이 사용했습니다.

  • Binary String 파싱: 16진수를 2진 문자열로 변환한 뒤 한 글자씩 잘라 해석
  • Bit Masking: 16 진수를 Bit Shift/AND 연산으로 즉석에서 비트를 해석

저는 메모리를 읽은 후 일단 16진수(Hexadecimal) 형태로 변환해서 확인하는 방식을 선호합니다.

16진수는 모든 byte 를 표현할 수 있기도 하고 무엇보다 사람이 읽을 수 있는 형태로 만들어놔야 로그로 확인하기에도 편하기 때문입니다.

Benchmark

이번엔 두 방식을 한번 측정해보려합니다.

설비에서 메모리를 읽어왔다고 가정하고 Hexadecimal 를 해석하여 최종적으로 각각의 비트를 boolean[16] 사이즈 배열로 만드는것이 목표입니다.

실제로 어떤 방식이 빠른지, 메모리 할당은 어떤 차이가 있는지 확인해보겠습니다.

bit mask vs binary string

벤치마크결과 Bit Mask 방식의 처리량이 Binary String 방식보다 약 50배 높게 측정되었습니다. 그리고 메모리 할당 관련해서도 20배 가량 차이가 있습니다.

자세한 코드는 Github 를 확인해 주시기 바랍니다.

측정 환경

항목값
Fork5
Warmup5 iterations x 10s
Measurement5 iterations x 10s
Cnt25 (Fork 5 x Measurement 5)
ModeThroughput
JMHv1.37
JDK21
OSmacOS (Darwin 25.6.0)

Bit Mask 가 빠른건 알지만…

String 객체는 문자열을 생성하고 처리하는 과정에서 객체 할당이나 추가적인 연산이 발생합니다. Bit Mask 방식에 비해 상대적으로 비용이 높고 느리다는 것은 대부분의 개발자가 알고있습니다.

그럼에도 불구하고 String으로 처리하는 것이 더 편한 경우가 있습니다. 물론 그 편한 대상은 사람이지만요.

크게 두 가지 경우가 있습니다.

  • 로그에 전체 Bit 상태를 보여줘야 할 때는 String이 직관적입니다.
  • Breakpoint를 걸고 디버깅할 때도 String 형태로 보는 것이 직관적입니다.

저도 내가 해석한 메모리가 서로 약속한 번지수에 알맞는 값인지 확인할땐 String 처리를 주로합니다.

성능만 생각하면 Bit Mask 가 더 적합할 수 있지만 사람이 값을 확인하고 디버깅하는 상황에선 String 이 더 유용할 때도 있습니다.

마치며

세상이 아무리 좋아져도 메모리를 아끼고싶고 최적화하고싶은건 모든 개발자의 공통된 마음인것 같습니다.

PC 개발자를 위해 1 Word == 1 의미 로 협의가 가능한 경우도 있긴 하지만 마음 한편 불편함은 어쩔수가 없습니다.

이번 글에서는 길브의 법칙처럼

Anything worth doing is worth measuring

평소에는 당연히 Bit Mask가 더 빠를 것이라고 생각했던 것을 직접 수치로 측정해보았습니다.

“무조건 Bit Mask를 사용해야 한다” 는 이야기를 하고자 하는것이 아닙니다.

결국 중요한 것은 ‘상황에 맞는 방법을 선택하는 것’ 입니다. 어떤 방법을 선택하건 그에따른 장단점이 무엇인지 어떤 Trade-Off 가 있는지 그 당시 어떤 이유로 선택했는지가 중요합니다.