Celper 업데이트를 위해 여러 라이브러리를 분석하던 중 뜬금없이 “왜?” 라는 의문이 드는 코드를 발견했다.
다음은 fastCSV의 코드에서 내부에 custom Buffer를 사용하는 부분이다.
각설하고 의문은 다음과 같았다. READ_SIZE는 상수이다. 근데 코드를 살펴보면 extendAndReloacate() 즉, buffer를 늘리는 코드가 존재한다. 그럼 READ_SIZE에 변화를 주어 더 많은 데이터를 읽도록 해야 한다고 생각했다. 하지만 코드에서는 고정된 READ_SIZE를 계속 사용한다.
여기서 “왜?” 라는 의문을 가졌다. “도와줘요 GPT” 를 외쳤다.
이유는 다음과 같다.
1. 고정 사이즈를 사용하는 이유는 메모리에 큰 데이터가 과적 될 수 있다.
2. 동일 사이즈 즉, 8192를 계속 읽으면 메모리 히트가 높아진다.
3. 가비지 컬렉션에 부하가 적어진다.
1번은 어느 정도 생각했다. 근데 2와 3은 예상 못했던 부분이다. 참고하면 좋을 것 같다.
private static class CsvBuffer implements Closeable {
private static final int READ_SIZE = 8192; // 문제의 상수
private static final int BUFFER_SIZE = READ_SIZE;
char[] buf;
int len;
int begin;
int pos;
..
private boolean fetchData() throws IOException {
if (reader == null) {
return false;
}
if (begin < pos) {
// we have data that can be relocated
if (READ_SIZE > buf.length - pos) {
// need to relocate data in buffer -- not enough capacity left
final int lenToCopy = pos - begin;
if (READ_SIZE > buf.length - lenToCopy) {
// need to relocate data in new, larger buffer
buf = extendAndRelocate(buf, begin);
} else {
// relocate data in existing buffer
System.arraycopy(buf, begin, buf, 0, lenToCopy);
}
pos -= begin;
begin = 0;
}
} else {
// all data was consumed -- nothing to relocate
pos = begin = 0;
}
final int cnt = reader.read(buf, pos, READ_SIZE); // 문제의 상수를 사용
if (cnt == -1) {
return false;
}
len = pos + cnt;
return true;
}
private static char[] extendAndRelocate(final char[] buf, final int begin) {
final int newBufferSize = buf.length * 2; // 문제의 새로운 Buffer Size
if (newBufferSize > Limits.MAX_FIELD_SIZE) {
throw new CsvParseException(String.format("The maximum buffer size of %d is "
+ "insufficient to read the data of a single field. "
+ "This issue typically arises when a quotation begins but does not conclude within the "
+ "confines of this buffer's maximum limit.",
Limits.MAX_FIELD_SIZE));
}
final char[] newBuf = new char[newBufferSize];
System.arraycopy(buf, begin, newBuf, 0, buf.length - begin);
return newBuf;
}
}
Java
복사