Object Pooling
- 오브젝트의 Pool을 만들어두고 해당 웅덩이 안에서 필요할 때마다 객체를 꺼내서 사용하는 것
- 잦은 오브젝트 할당으로 인한 오버헤드가 감소된다.
GenericObjectPool
Apache Commons Pool 라이브러리의 일부로서 객체 풀링(object pooling)을 구현하기 위한 클래스 중 하나입니다.
- 객체 풀은 자주 생성 및 소멸되는 객체를 관리하고 재사용함으로써 성능을 최적화하는데 사용합니다.
- 일반적으로는 데이터베이스 연결, 소켓 연결, 스레드 등과 같이 생성 및 제거 비용이 높은 리소스를 효율적으로 사용하는 데 도움이 됩니다.
특징
- 커스터마이징 가능한 구성 : 객체 풀을 구성할 수 있는 다양한 설정을 제공 합니다
- 최소 및 최대 객체 수, 리소스 생성 및 제거, 오브젝트 유효성 검사
- 객체 리사이클링 : 객체가 사용한 후에 풀로 반환되며, 다른 클라이언트가 재사용할 수 있도록 풀에서 관리됩니다.
- 객체 유효성 검사 : 풀에서 가져오는 객체가 유효한지 확인하기 위한 사용자 정의 검증로직을 지원합니다. 유효성 검사에 실패하는 경우 해당 객체는 폐기됩니다.
- Blocking 및 Non-blocking 동작 : 클라이언트가 객체를 요청했을 때, 객체가 사용 가능하지 않은 경우 Blocking 및 Non-blocking 동작을 지원합니다.
- 객체 고정화 클래스 : PooledObject 인터페이스를 구현하여 객체의 생명주기를 추적하고 관리합니다.
이와 같이 GenericObjectpol은 객체 풀을 구현하고 사용자 정의 리소스를 관리하는데 매우 유용합니다. 이를 통해 메모리와 리소스 사용을 최적화하고, 속도와 성능을 향상 시킬 수 있습니다.
Java에서 사용해보기
gradle
implementation 'commons-pool:commons-pool:1.6'
Clone.java
@Getter
@Setter
public class Clone {
private long id;
private String name;
private static int count;
public Clone() {
count++;
}
}
ClonePool.java
@Component
public class ClonePool extends BasePoolableObjectFactory<Clone> {
@Override
public Clone makeObject() throws Exception {
return new Clone();
}
}
테스트 코드
1) 반환 X
@Slf4j
@SpringBootTest
public class PoolTest {
@Test
public void poolTest() throws Exception {
GenericObjectPool genericObjectPool = new GenericObjectPool(new ClonePool());
log.info("===============start==============");
for (int i = 0; i < 10; i++) {
Clone clone = (Clone)genericObjectPool.borrowObject();
log.info(clone + ", " + Clone.getCount());
}
log.info("===============close==============");
}
}
borrowObject를 통해서 객체를 풀링하고 다시 반환을 하지 않았기 때문에 객체 풀의 객체 디폴트 제한 값인 8에서 객체를 더 풀링해오지 못하고 멈춘 것을 확인할 수 있다.
com.dnd.jpatest.PoolTest : ===============start==============
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@43e9a8a2, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@178617da, 2
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 3
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@74ed1d35, 4
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@7acf07b2, 5
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@5d50e7f6, 6
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@54fbaa65, 7
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@48e3017a, 8
2) 반환 O
@Slf4j
@SpringBootTest
public class PoolTest {
@Test
public void poolTest() throws Exception {
GenericObjectPool genericObjectPool = new GenericObjectPool(new ClonePool());
log.info("===============start==============");
for (int i = 0; i < 1000; i++) {
Clone clone = (Clone)genericObjectPool.borrowObject();
log.info(clone + ", " + Clone.getCount());
genericObjectPool.returnObject(clone);
}
log.info("===============close==============");
}
}
com.dnd.jpatest.PoolTest : ===============start==============
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@d408c5d, 1
com.dnd.jpatest.PoolTest : ===============close==============
borrowObject 후 returnObject를 통해 객체를 반환하기 때문에 count도 계속 1이고 같은 객체를 가져오는 것을 확인할 수 있다.
3) 객체 삭제
@Slf4j
@SpringBootTest
public class PoolTest {
@Test
public void poolTest() throws Exception {
GenericObjectPool genericObjectPool = new GenericObjectPool(new ClonePool());
log.info("===============start==============");
for (int i = 0; i < 10; i++) {
Clone clone = (Clone)genericObjectPool.borrowObject();
log.info(clone + ", " + Clone.getCount());
genericObjectPool.invalidateObject(clone);
}
log.info("===============close==============");
}
}
returnObject → inavalidObject로 변경하였습니다.
com.dnd.jpatest.PoolTest : ===============start==============
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@54fbaa65, 1
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@48e3017a, 2
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@4a937d43, 3
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@10264cb0, 4
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@19877453, 5
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@49bf5ec8, 6
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@18174bd9, 7
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@3af6d7a7, 8
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@18711946, 9
com.dnd.jpatest.PoolTest : com.dnd.jpatest.Clone@2b8b5d9e, 10
com.dnd.jpatest.PoolTest : ===============close==============
반환된 객체가 아닌 새로운 객체가 생성되기 때문에 객체의 주소가 다르고, count 값이 증가됩니다.
Config
@Configuration
public class ObjectPoolConfig {
@Bean
public GenericObjectPool objectnPool() {
GenericObjectPool pool = new GenericObjectPool(new ClonePool());
pool.setMaxActive(10); // 최대 객체 풀 수
pool.setMaxIdle(5); // 최대 비활성 객체 수
pool.setMinIdle(2); // 최소 비활성 객체 수
return pool;
}
}
Config 파일을 통해 객체 풀에 대한 초기 설정을 할 수 있다.
'Java' 카테고리의 다른 글
Java Executors, ExecutorService (0) | 2024.05.31 |
---|---|
OpenSearch를 사용하면서 발생한 문제 (0) | 2023.11.02 |
[JAVA] Socket 연결 시 Timeout 설정 (0) | 2023.10.20 |
[Java] try-with-resource (AutoCloseable) (0) | 2023.09.25 |
[Java] - Synchronized (0) | 2023.09.22 |