현대 AI 가속기는 용량, 대역폭 및 지연 시간의 균형을 맞추도록 설계된 복잡한 메모리 계층을 특징으로 합니다. 이 계층을 이해하는 것은 효율적인 메모리 관리에 필수적입니다.
| 메모리 레벨 | 용량 | 대역폭 | 지연시간 | 용도 |
|---|---|---|---|---|
| 레지스터 | 수 KB | 수십 TB/s | 1 사이클 | 커널 내 임시 변수 |
| 공유 메모리/L1 캐시 | 수십-수백 KB | 수 TB/s | 수십 사이클 | 작업 그룹 데이터 공유 |
| L2 캐시 | 수 MB | 1-10 TB/s | 수백 사이클 | 컴퓨팅 유닛 간 데이터 |
| HBM/GDDR | 16-80 GB | 900-2500 GB/s | 수백 사이클 | 주 작업 데이터 |
| 시스템 DRAM | 수백 GB | 50-100 GB/s | 수천 사이클 | 입력/출력 데이터 |
// 메모리 계층 활용 예제
__kernel void optimized_matmul(
__global const float* A,
__global const float* B,
__global float* C,
int N
) {
// 1. 공유 메모리 활용 (빠른 접근)
__local float tile_A[16][16];
__local float tile_B[16][16];
// 2. 레지스터 활용 (가장 빠름)
float sum = 0.0f;
int row = get_local_id(0);
int col = get_local_id(1);
// 3. HBM에서 공유 메모리로 타일 로드
for (int tile = 0; tile < N/16; tile++) {
// 협력하여 타일 로드 (메모리 통합)
tile_A[row][col] = A[...];
tile_B[row][col] = B[...];
barrier(CLK_LOCAL_MEM_FENCE); // 동기화
// 4. 공유 메모리에서 계산 (빠른 액세스)
for (int k = 0; k < 16; k++) {
sum += tile_A[row][k] * tile_B[k][col];
}
barrier(CLK_LOCAL_MEM_FENCE);
}
// 5. 레지스터에서 HBM으로 결과 저장
C[...] = sum;
}
WIA-AI-011은 다양한 사용 패턴에 최적화된 여러 할당 전략을 지원합니다.
// 버디 할당자 구현
typedef struct {
size_t size;
bool is_free;
struct block* left_buddy;
struct block* right_buddy;
} memory_block_t;
void* buddy_alloc(size_t size) {
// 1. 요청 크기를 2의 거듭제곱으로 반올림
size_t rounded_size = next_power_of_2(size);
// 2. 적합한 블록 찾기
memory_block_t* block = find_free_block(rounded_size);
// 3. 블록이 너무 크면 분할
while (block->size > rounded_size * 2) {
split_block(block); // 버디로 분할
}
// 4. 블록 할당
block->is_free = false;
return block->data;
}
void buddy_free(void* ptr) {
memory_block_t* block = get_block(ptr);
block->is_free = true;
// 버디와 병합 시도 (단편화 감소)
while (block->buddy && block->buddy->is_free) {
merge_buddies(block, block->buddy);
}
}
// 슬랩 할당자 - 고정 크기 객체에 최적
typedef struct {
size_t object_size;
size_t objects_per_slab;
void* free_list; // 사용 가능 객체 목록
} slab_t;
slab_t* create_slab(size_t object_size) {
slab_t* slab = malloc(sizeof(slab_t));
slab->object_size = object_size;
slab->objects_per_slab = 256; // 슬랩당 256개 객체
// 슬랩 메모리 할당
void* slab_mem = aligned_alloc(256,
object_size * slab->objects_per_slab);
// 프리 리스트 초기화
for (int i = 0; i < slab->objects_per_slab - 1; i++) {
void* obj = slab_mem + i * object_size;
*(void**)obj = slab_mem + (i + 1) * object_size;
}
slab->free_list = slab_mem;
return slab;
}
void* slab_alloc(slab_t* slab) {
// O(1) 할당
if (!slab->free_list) {
return NULL; // 슬랩 가득 참
}
void* obj = slab->free_list;
slab->free_list = *(void**)obj; // 다음으로 이동
return obj;
}
void slab_free(slab_t* slab, void* obj) {
// O(1) 해제
*(void**)obj = slab->free_list;
slab->free_list = obj;
}
통합 메모리는 CPU와 가속기 모두에서 액세스할 수 있는 단일 주소 공간을 제공하여 프로그래밍을 단순화합니다.
// 통합 메모리 사용 예제
void process_data_unified() {
// 1. 통합 메모리 할당
float* data = wia_alloc_unified(ctx, size);
// 2. CPU에서 초기화 (자동 마이그레이션)
for (int i = 0; i < n; i++) {
data[i] = initialize_value(i);
}
// 3. GPU에서 계산 (런타임이 자동 전송)
wia_compute_kernel<<>>(data, n);
// 4. CPU에서 결과 읽기 (자동 전송)
float result = data[0];
// 5. 정리
wia_free_unified(data);
}
// 명시적 힌트로 성능 최적화
void process_with_hints() {
float* data = wia_alloc_unified(ctx, size);
// CPU에서 주로 사용될 것임을 힌트
wia_advise_memory(data, size, WIA_MEM_ADVISE_CPU_PREFER);
// CPU 초기화
initialize_on_cpu(data, n);
// GPU로 프리페치 (미리 전송)
wia_prefetch_async(data, size, device, stream);
// GPU 계산
wia_compute_kernel<<>>(data, n);
wia_free_unified(data);
}
고정(페이지 잠금) 메모리는 CPU 개입 없이 DMA 전송을 가능하게 하여 호스트-디바이스 대역폭을 극적으로 향상시킵니다.
// 고정 메모리 vs 일반 메모리 성능 비교
void compare_transfer_performance() {
size_t size = 1024 * 1024 * 1024; // 1GB
// 1. 일반 메모리 (페이징 가능)
float* pageable_host = malloc(size);
float* device_mem = wia_alloc_device(ctx, size);
double start = get_time();
wia_copy_h2d(device_mem, pageable_host, size);
double pageable_time = get_time() - start;
// 2. 고정 메모리 (페이징 불가)
float* pinned_host = wia_alloc_pinned(ctx, size);
start = get_time();
wia_copy_h2d(device_mem, pinned_host, size);
double pinned_time = get_time() - start;
printf("일반 메모리 전송: %.3f ms (%.2f GB/s)\n",
pageable_time * 1000,
size / pageable_time / 1e9);
printf("고정 메모리 전송: %.3f ms (%.2f GB/s)\n",
pinned_time * 1000,
size / pinned_time / 1e9);
printf("속도 향상: %.2fx\n", pageable_time / pinned_time);
// 일반적으로 3-5배 빠름
free(pageable_host);
wia_free_pinned(pinned_host);
wia_free_device(device_mem);
}
반복적인 할당과 해제는 단편화와 오버헤드를 유발합니다. 메모리 풀은 해제된 버퍼를 캐시에 유지하여 O(1) 재할당을 가능하게 합니다.
// 고급 메모리 풀 구현
typedef struct {
size_t size_class;
wia_memory_t** cache; // LRU 캐시
int cache_size;
int cache_capacity;
} size_class_pool_t;
typedef struct {
size_class_pool_t* pools[32]; // 다양한 크기 클래스
wia_mutex_t lock;
size_t total_allocated;
size_t peak_allocated;
} memory_pool_t;
wia_memory_t* pool_alloc(memory_pool_t* pool, size_t size) {
// 1. 크기 클래스 결정
int size_class = get_size_class(size);
size_class_pool_t* class_pool = pool->pools[size_class];
wia_mutex_lock(&pool->lock);
// 2. 캐시에서 검색
if (class_pool->cache_size > 0) {
wia_memory_t* mem = class_pool->cache[--class_pool->cache_size];
wia_mutex_unlock(&pool->lock);
return mem; // 캐시 적중 - O(1)
}
wia_mutex_unlock(&pool->lock);
// 3. 캐시 미스 - 새로 할당
wia_memory_t* mem = wia_alloc_device(ctx, size_class_size(size_class));
pool->total_allocated += size_class_size(size_class);
if (pool->total_allocated > pool->peak_allocated) {
pool->peak_allocated = pool->total_allocated;
}
return mem;
}
void pool_free(memory_pool_t* pool, wia_memory_t* mem) {
size_t size = wia_memory_size(mem);
int size_class = get_size_class(size);
size_class_pool_t* class_pool = pool->pools[size_class];
wia_mutex_lock(&pool->lock);
// 캐시에 공간이 있으면 저장 (실제 해제 안 함)
if (class_pool->cache_size < class_pool->cache_capacity) {
class_pool->cache[class_pool->cache_size++] = mem;
wia_mutex_unlock(&pool->lock);
return;
}
wia_mutex_unlock(&pool->lock);
// 캐시 가득참 - LRU 제거 후 실제 해제
wia_free_device(class_pool->cache[0]);
memmove(class_pool->cache, class_pool->cache + 1,
(class_pool->cache_size - 1) * sizeof(wia_memory_t*));
class_pool->cache[class_pool->cache_size - 1] = mem;
}
수동 메모리 관리는 오류가 발생하기 쉽습니다. WIA-AI-011은 메모리 버퍼에 대한 선택적 참조 카운팅 및 가비지 컬렉션을 지원합니다.
// 참조 카운팅 메모리 관리
typedef struct {
void* data;
size_t size;
atomic_int ref_count;
wia_device_t* device;
} ref_counted_memory_t;
ref_counted_memory_t* create_ref_counted(size_t size) {
ref_counted_memory_t* mem = malloc(sizeof(ref_counted_memory_t));
mem->data = wia_alloc_device(ctx, size);
mem->size = size;
atomic_init(&mem->ref_count, 1); // 초기 참조 = 1
return mem;
}
void retain_memory(ref_counted_memory_t* mem) {
atomic_fetch_add(&mem->ref_count, 1);
}
void release_memory(ref_counted_memory_t* mem) {
int old_count = atomic_fetch_sub(&mem->ref_count, 1);
if (old_count == 1) {
// 마지막 참조 해제 - 메모리 반환
wia_free_device(mem->data);
free(mem);
}
}
// 사용 예제
void shared_memory_example() {
// 메모리 생성 (ref_count = 1)
ref_counted_memory_t* mem = create_ref_counted(1024 * 1024);
// 다른 컴포넌트와 공유
retain_memory(mem); // ref_count = 2
process_in_thread_a(mem);
retain_memory(mem); // ref_count = 3
process_in_thread_b(mem);
// 각 컴포넌트가 완료 후 해제
release_memory(mem); // ref_count = 2
// ... thread_a 완료
release_memory(mem); // ref_count = 1
// ... thread_b 완료
release_memory(mem); // ref_count = 0, 메모리 해제됨
}
장시간 실행되는 애플리케이션은 메모리 단편화로 고통받습니다. WIA-AI-011은 라이브 버퍼를 재배치하여 여유 공간을 통합하는 압축 알고리즘을 구현합니다.
// 메모리 조각 모음 (압축) 알고리즘
typedef struct {
void* address;
size_t size;
bool is_free;
wia_tensor_t* owner; // 참조 업데이트용
} memory_block_t;
void defragment_memory(wia_context_t* ctx) {
memory_block_t* blocks = get_all_blocks(ctx);
int num_blocks = get_num_blocks(ctx);
// 1. 사용 중인 블록을 앞으로 이동
void* compact_base = get_heap_base(ctx);
for (int i = 0; i < num_blocks; i++) {
if (!blocks[i].is_free) {
// 블록을 새 위치로 이동
void* new_addr = compact_base;
if (new_addr != blocks[i].address) {
// 디바이스 내 메모리 복사
wia_copy_device_to_device(
new_addr, blocks[i].address, blocks[i].size
);
// 텐서 포인터 업데이트
if (blocks[i].owner) {
update_tensor_pointer(blocks[i].owner, new_addr);
}
}
// 다음 블록 위치
compact_base += blocks[i].size;
}
}
// 2. 남은 공간을 하나의 큰 여유 블록으로 병합
size_t free_size = get_heap_end(ctx) - compact_base;
create_free_block(compact_base, free_size);
printf("조각 모음 완료: %.1f%% 공간 회수\n",
(float)free_size / get_total_memory(ctx) * 100);
}
여러 가속기를 사용하는 애플리케이션은 디바이스 간 메모리를 관리해야 합니다.
// 피어 투 피어 메모리 액세스
void enable_peer_access_example() {
wia_device_t* gpu0 = wia_get_device(0);
wia_device_t* gpu1 = wia_get_device(1);
// 1. P2P 지원 확인
bool can_p2p = wia_can_access_peer(gpu0, gpu1);
if (can_p2p) {
// 2. P2P 액세스 활성화
wia_enable_peer_access(gpu0, gpu1);
// 3. GPU0에 메모리 할당
wia_tensor_t* tensor = wia_create_tensor(gpu0, shape);
// 4. GPU1에서 직접 액세스 (복사 없음!)
wia_compute_on_device(gpu1, tensor);
// 대역폭: 50-100 GB/s (NVLink) vs 10-15 GB/s (PCIe)
} else {
// P2P 불가 - 명시적 복사 필요
wia_tensor_t* tensor_gpu0 = wia_create_tensor(gpu0, shape);
wia_tensor_t* tensor_gpu1 = wia_create_tensor(gpu1, shape);
wia_copy_peer(tensor_gpu1, tensor_gpu0);
wia_compute_on_device(gpu1, tensor_gpu1);
}
}
// NUMA 인식 할당
wia_tensor_t* alloc_numa_aware(int preferred_device) {
wia_device_t* device = wia_get_device(preferred_device);
wia_numa_node_t numa_node = wia_get_numa_node(device);
// NUMA 노드에 가까운 메모리 할당
wia_tensor_t* tensor = wia_create_tensor_numa(
device, shape, numa_node
);
return tensor;
}
메모리 대역폭은 종종 가속기 성능을 제한합니다.
// 메모리 통합 (Coalescing) 예제
__kernel void uncoalesced_access(
__global float* data,
int stride
) {
int gid = get_global_id(0);
// 나쁨: 스트라이드 액세스 (통합되지 않음)
float value = data[gid * stride];
// ...
}
__kernel void coalesced_access(
__global float* data,
int N
) {
int gid = get_global_id(0);
// 좋음: 연속 액세스 (통합됨)
float value = data[gid];
// 32-128배 빠를 수 있음
}
// 뱅크 충돌 회피
__kernel void avoid_bank_conflicts() {
__local float shared[256];
int lid = get_local_id(0);
// 나쁨: 뱅크 충돌
shared[lid * 2] = ...; // 홀수 뱅크만 사용
// 좋음: 패딩으로 충돌 회피
__local float shared_padded[256 + 32];
shared_padded[lid] = ...; // 모든 뱅크 사용
}
// 이중 버퍼링으로 지연 숨기기
void double_buffering_example() {
wia_memory_t* buffer_a = wia_alloc_device(ctx, size);
wia_memory_t* buffer_b = wia_alloc_device(ctx, size);
for (int i = 0; i < num_batches; i++) {
if (i % 2 == 0) {
// 버퍼 A: 계산, 버퍼 B: 전송
wia_compute_async(buffer_a, stream_compute);
wia_copy_async(host_data[i+1], buffer_b, stream_transfer);
} else {
// 버퍼 B: 계산, 버퍼 A: 전송
wia_compute_async(buffer_b, stream_compute);
wia_copy_async(host_data[i+1], buffer_a, stream_transfer);
}
}
}
메모리 오류는 미묘한 버그와 보안 취약점을 유발합니다.
// 메모리 안전 기능
#ifdef WIA_DEBUG_MEMORY
// 1. 경계 검사
void* safe_alloc(size_t size) {
// 가드 페이지 추가
size_t guard_size = 4096;
size_t total_size = size + 2 * guard_size;
void* ptr = wia_alloc_device(ctx, total_size);
// 가드 페이지를 보호 모드로 설정
wia_protect_memory(ptr, guard_size, WIA_PROT_NONE);
wia_protect_memory(ptr + guard_size + size, guard_size, WIA_PROT_NONE);
return ptr + guard_size;
}
// 2. 사용 후 해제 감지
typedef struct {
void* ptr;
size_t size;
bool is_freed;
const char* alloc_site;
const char* free_site;
} allocation_record_t;
void track_allocation(void* ptr, size_t size) {
allocation_record_t record = {
.ptr = ptr,
.size = size,
.is_freed = false,
.alloc_site = __FILE__ ":" STRINGIFY(__LINE__)
};
add_to_tracker(&record);
}
void safe_free(void* ptr) {
allocation_record_t* record = find_allocation(ptr);
if (!record) {
fprintf(stderr, "오류: 할당되지 않은 메모리 해제 시도\n");
abort();
}
if (record->is_freed) {
fprintf(stderr, "오류: 이중 해제 감지\n");
fprintf(stderr, " 할당 위치: %s\n", record->alloc_site);
fprintf(stderr, " 첫 해제: %s\n", record->free_site);
fprintf(stderr, " 두 번째 해제: %s:%d\n", __FILE__, __LINE__);
abort();
}
record->is_freed = true;
record->free_site = __FILE__ ":" STRINGIFY(__LINE__);
wia_free_device(ptr);
}
// 3. 누수 감지
void detect_leaks() {
for (int i = 0; i < num_allocations; i++) {
if (!allocations[i].is_freed) {
fprintf(stderr, "메모리 누수 감지:\n");
fprintf(stderr, " 주소: %p\n", allocations[i].ptr);
fprintf(stderr, " 크기: %zu bytes\n", allocations[i].size);
fprintf(stderr, " 할당 위치: %s\n", allocations[i].alloc_site);
}
}
}
#endif // WIA_DEBUG_MEMORY
한국은 삼성전자 HBM3E (8-Hi 24GB·12-Hi 36GB)·HBM4 (양산 2025)·SK하이닉스 HBM3E 12-Hi/16-Hi·삼성 MRDIMM·SK CXL 1.1/2.0/3.0 메모리 풀·LPDDR5X-9600·삼성 LPCAMM2·SK하이닉스 GDDR7 등 글로벌 1위 HBM 인프라를 보유한다. ETRI·KAIST·서울대 반도체공동연구소·KIST 「반도체 메모리 연구단」·KISTI·NIPA·IITP·KETI 협력 「K-Memory 2030」 로드맵에 따라 CXL 3.0/3.1·UCIe 1.1/2.0·OpenCAPI 호환 메모리 풀링·메모리 시멘틱 패브릭 한국 프로파일이 KS X ISO/IEC 표준으로 발행 중이다. 한국 NPU 8사 (리벨리온·퓨리오사·사피온·딥엑스·삼성·LG·SK·현대모비스) 가 CXL·HBM·LPDDR 통합 메모리 계층을 지원한다.
한국의 산업·기술 표준화는 다음 협력 체계를 통해 운영된다. 국가표준 거버넌스: 국가표준심의회(국무총리실 소속, 「국가표준기본법」 제5조)·국가기술표준원(KATS)·식품의약품안전처(MFDS)·산업통상자원부(MOTIE)·과학기술정보통신부(MSIT)·행정안전부(MOIS)·환경부(MOE)·보건복지부(MOHW)·국방부(MND)·문화체육관광부(MCST)·외교부(MOFA)·법무부(MOJ)·금융위원회(FSC). 한국 인정기구·시험기관: 한국인정기구(KOLAS, Korea Laboratory Accreditation Scheme)·한국제품인정기관(KAS)·한국시험인증연구원(KTC)·한국화학융합시험연구원(KTR)·한국산업기술시험원(KTL)·한국건설생활환경시험연구원(KCL)·KOLAS 인정 시험기관 800+개·KAS 인정 인증기관 50+개. 전기·전자·통신 인증: 방송통신위원회(KCC)·한국방송통신전파진흥원(KCA)·정보통신기술협회(TTA)·정보통신기획평가원(IITP)·정보통신산업진흥원(NIPA)·한국인터넷진흥원(KISA, Korea Internet & Security Agency)·KCMVP (국가용 암호모듈 검증제도)·NIS(국가정보원)·NSR(국가보안기술연구소)·NCSC(국가사이버안보센터). 국가 R&D 거점: 한국과학기술연구원(KIST)·한국전자통신연구원(ETRI)·한국과학기술원(KAIST)·서울대학교·연세대학교·고려대학교·POSTECH·UNIST·GIST·DGIST·한국과학기술정보연구원(KISTI)·한국에너지기술연구원(KIER)·한국기계연구원(KIMM)·한국화학연구원(KRICT)·한국식품연구원(KFRI)·한국생명공학연구원(KRIBB). 국제 표준 협력: ISO TC/SC 한국 간사·IEC TC/SC 한국 간사·ITU-T SG 한국 의장·3GPP RAN/SA 한국 의장·IEEE 802 한국 의장·W3C 한국지부·OASIS 한국지부·IETF 한국 협력단·OECD CSTP·UN ESCAP·APEC SCSC 한국 협력. 한국 표준 카탈로그: KS X (정보) 25,000+종·KS A (기본) 15,000+종·KS B (기계) 25,000+종·KS C (전기) 18,000+종·KS D (금속) 12,000+종·KS E (광산) 5,000+종·KS F (건설) 18,000+종·KS H (식품) 8,000+종·KS I (환경) 5,000+종·KS J (생물) 3,000+종·KS K (섬유) 15,000+종·KS L (요업) 7,000+종·KS M (화학) 12,000+종·KS P (의료) 5,000+종·KS Q (품질) 4,000+종·KS R (수송기계) 12,000+종·KS S (서비스) 3,000+종·KS T (포장) 4,000+종·KS V (조선) 5,000+종·KS W (항공) 3,000+종 — 총 220,000+ 한국산업표준(KS). 「개인정보 보호법」(법률 제19234호, 2024년 9월 15일 시행)·「전자정부법」·「전자서명법」·「정보통신망법」·「정보통신기반 보호법」·「데이터 산업법」·「공공데이터법」·「인공지능 기본법」(법률 제20212호, 2026년 7월 시행)·「산업기술혁신 촉진법」·「과학기술기본법」 등 70+개 한국 표준화 관련 법령이 운영된다.
한국의 디지털 전환과 표준화는 다음 협력 체계로 운영된다. 디지털 정부: 디지털플랫폼정부위원회(2022년 9월 신설, 대통령 직속)·행정안전부 디지털정부국·전자정부지원센터·정부24·국민비서·KDIS(한국정보화진흥원)·NIA(한국지능정보사회진흥원)·MOIS(행정안전부). K-DNS 인프라: 한국인터넷진흥원(KISA) Korea Internet Center·KISA DNS Root Server·KRNIC(한국인터넷정보센터)·BGP Korea·국가사이버안보센터(NCSC)·KCC(방송통신위원회)·과기정통부(MSIT)·NIA·NIPA. 한국 클라우드 인프라: KT 클라우드·NAVER 클라우드 (NCloud)·삼성 SDS 클라우드·LG U+ 클라우드·NHN 클라우드·카카오엔터프라이즈 클라우드·SK텔레콤 클라우드·KISA 「클라우드 보안 인증제(CSAP)」·KCMVP 검증 클라우드·ISMS-P (정보보호 및 개인정보보호 관리체계). 한국 보안 인증: KISA ISMS-P 인증·KCMVP (국가용 암호모듈 검증제도)·국가정보원 NIS 「국가용 암호기술 운영기준」·NCSC 「국가사이버안보전략 2024-2028」·CC (Common Criteria) 한국 평가기관·EAL4·EAL5·KS X ISO/IEC 15408·19790·24759 한국 프로파일. 한국 데이터 표준: 한국지능정보사회진흥원(NIA) AI Hub·국가 데이터 표준화 위원회·통계청(KOSTAT)·MyData 4개 결합전문기관 (삼성SDS·한국신용정보원·통계청·금융결제원)·국립국어원 한국어 정보처리 표준·국가법령정보센터·국가공간정보플랫폼·국가공간데이터센터·한국공간정보표준. 금융·핀테크 표준: 금융위원회(FSC)·금융감독원(FSS)·금융정보분석원(FIU)·한국은행(BOK)·금융보안원(FSEC)·금융결제원(KFTC)·한국예탁결제원(KSD)·한국거래소(KRX) 8개 기관 협력. 5G/6G 통신 인프라: 5G 가입자 3,500만 명 (2024)·5G 기지국 350,000개·6G 상용화 목표 2028년·5G 특화망 16개 사업자·6G 가속화 추진단(MSIT, 2024) 운영. K-콘텐츠: 한국콘텐츠진흥원(KOCCA)·문화체육관광부(MCST)·한국방송통신전파진흥원(KCA)·한국문화정보원·한국영상자료원·한국출판문화산업진흥원. 「데이터3법」 (개인정보 보호법·신용정보법·정보통신망법, 2020년 시행)·「데이터 산업법」(2021)·「공공데이터법」(2013)·「인공지능 기본법」(2026)·「디지털플랫폼정부 기본법」(2024 발의) 등 한국 디지털 전환 핵심 법령이 운영 중이다.