본문 바로가기
Development/Java

[Java] Java System.arraycopy 사용 방법 및 성능 비교

by 은스타 2019. 9. 4.
반응형
Java System.arraycopy 사용 방법 및 성능 비교

Java System.arraycopy 사용 방법 및 성능 비교

개요

안녕하세요. 이번 포스팅은 Java에서 배열을 효율적으로 복사하는 핵심 메서드인 System.arraycopy에 대해 상세히 알아보겠습니다. 대용량 데이터를 다루거나 성능이 중요한 애플리케이션을 개발할 때 배열 복사 방법은 프로그램의 속도와 메모리 사용에 큰 영향을 미칩니다. 이 글에서는 System.arraycopy의 기본 개념부터 고급 활용법, 성능 분석까지 모든 것을 다루어 여러분의 코딩 실력을 한 단계 업그레이드하는 데 도움을 드리겠습니다.
목차
1. System.arraycopy란?
2. 기본 문법과 매개변수
3. System.arraycopy 사용 예제
4. 다양한 데이터 타입 복사하기
5. 성능 분석과 다른 복사 방법 비교

#1. System.arraycopy란?
System.arraycopy는 Java의 표준 라이브러리에 포함된 네이티브 메서드로, 한 배열에서 다른 배열로 요소를 빠르게 복사하는 기능을 제공합니다. 이 메서드는 JDK 1.0부터 제공되어 왔으며, Java의 가장 기본적이면서도 강력한 배열 조작 도구 중 하나입니다.
1) 주요 특징
네이티브 메서드: C/C++로 구현되어 JVM의 최적화된 성능을 제공
빠른 속도: 자바의 다른 배열 복사 방법보다 일반적으로 더 빠름
메모리 효율성: 새 배열을 생성하지 않고 기존 배열로 직접 복사 가능
부분 복사: 배열의 특정 부분만 선택적으로 복사 가능
다양한 타입 지원: 기본 데이터 타입과 객체 배열 모두 지원
.....
2) 내부 동작 원리
System.arraycopy는 Java Native Interface(JNI)를 통해 구현된 네이티브 메서드입니다. 내부적으로는 C/C++로 작성되어 있어 JVM이 직접 최적화된 메모리 복사 작업을 수행합니다.
(1) 메모리 블록 복사
배열은 연속된 메모리 공간에 저장되므로, 시스템 수준에서 효율적인 메모리 블록 복사 연산이 수행됩니다.
(2) 타입 검사
JVM은 복사 과정에서 배열 타입의 호환성을 검사합니다. 호환되지 않는 타입의 배열 간 복사를 시도하면 ArrayStoreException이 발생합니다.
(3) 경계 검사
원본 및 대상 배열의 인덱스와 길이가 유효한지 검사합니다. 배열 범위를 벗어나면 IndexOutOfBoundsException이 발생합니다.

#2. 기본 문법과 매개변수
System.arraycopy 메서드의 기본 문법은 다음과 같습니다.
// 기본 문법
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
1) 매개변수 설명
No 매개변수 설명
1 src 원본 배열 (복사할 데이터가 있는 배열)
2 srcPos 원본 배열에서 복사를 시작할 인덱스
3 dest 대상 배열 (데이터가 복사될 배열)
4 destPos 대상 배열에서 데이터를 저장할 시작 인덱스
5 length 복사할 요소의 개수
.....
2) 간단한 예시
int[] source = {1, 2, 3, 4, 5};
int[] destination = new int[5];

// source 배열의 내용을 destination 배열로 복사
System.arraycopy(source, 0, destination, 0, source.length);

// 결과: destination = {1, 2, 3, 4, 5}

#3. System.arraycopy 사용 예제
실제 코드를 통해 System.arraycopy의 다양한 사용법을 알아보겠습니다.
1) 전체 배열 복사
public class ArrayCopyExample1 {
    public static void main(String[] args) {
        int[] sourceArray = {1, 2, 3, 4, 5};
        int[] destArray = new int[sourceArray.length];

        // 전체 배열 복사
        System.arraycopy(sourceArray, 0, destArray, 0, sourceArray.length);

        // 결과 출력
        System.out.print("복사된 배열: ");
        for (int value : destArray) {
            System.out.print(value + " ");
        }
        // 출력 결과: 복사된 배열: 1 2 3 4 5
    }
}
.....
2) 배열의 일부분만 복사
public class ArrayCopyExample2 {
    public static void main(String[] args) {
        int[] sourceArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        int[] destArray = new int[5];

        // 원본 배열의 인덱스 3부터 5개 요소를 대상 배열의 인덱스 0부터 복사
        System.arraycopy(sourceArray, 3, destArray, 0, 5);

        // 결과 출력
        System.out.print("부분 복사된 배열: ");
        for (int value : destArray) {
            System.out.print(value + " ");
        }
        // 출력 결과: 부분 복사된 배열: 4 5 6 7 8
    }
}
.....
3) 동일한 배열 내에서 요소 이동
public class ArrayCopyExample3 {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5};

        // 인덱스 0부터 3개 요소를 같은 배열의 인덱스 1로 이동
        // 주의: 이렇게 하면 array[0]의 값은 유지됨
        System.arraycopy(array, 0, array, 1, 3);

        // 결과 출력
        System.out.print("요소 이동 후 배열: ");
        for (int value : array) {
            System.out.print(value + " ");
        }
        // 출력 결과: 요소 이동 후 배열: 1 1 2 3 5
    }
}
.....
4) 배열의 특정 요소 삭제
public class ArrayCopyExample4 {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5};
        int removeIndex = 2; // 인덱스 2(값 3)를 삭제

        // 삭제할 요소 다음부터 끝까지의 요소들을 한 칸씩 앞으로 이동
        System.arraycopy(array, removeIndex + 1, array, removeIndex,
                         array.length - removeIndex - 1);

        // 마지막 요소는 0으로 설정
        array[array.length - 1] = 0;

        // 결과 출력
        System.out.print("요소 삭제 후 배열: ");
        for (int value : array) {
            System.out.print(value + " ");
        }
        // 출력 결과: 요소 삭제 후 배열: 1 2 4 5 0
    }
}

#4. 다양한 데이터 타입 복사하기
System.arraycopy는 기본 데이터 타입과 객체 배열 모두에 사용할 수 있습니다.
1) 기본 데이터 타입 배열 복사
(1) byte 배열 복사
byte[] srcBytes = {1, 2, 3, 4, 5};
byte[] destBytes = new byte[srcBytes.length];
System.arraycopy(srcBytes, 0, destBytes, 0, srcBytes.length);
(2) char 배열 복사
char[] srcChars = {'a', 'b', 'c', 'd', 'e'};
char[] destChars = new char[srcChars.length];
System.arraycopy(srcChars, 0, destChars, 0, srcChars.length);
(3) boolean 배열 복사
boolean[] srcBooleans = {true, false, true, false, true};
boolean[] destBooleans = new boolean[srcBooleans.length];
System.arraycopy(srcBooleans, 0, destBooleans, 0, srcBooleans.length);
(4) double 배열 복사
double[] srcDoubles = {1.1, 2.2, 3.3, 4.4, 5.5};
double[] destDoubles = new double[srcDoubles.length];
System.arraycopy(srcDoubles, 0, destDoubles, 0, srcDoubles.length);
.....
2) 객체 배열 복사 (얕은 복사)
public class ObjectArrayCopyExample {
    static class Person {
        String name;
        int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }

    public static void main(String[] args) {
        // 객체 배열 생성
        Person[] sourcePeople = {
            new Person("Alice", 25),
            new Person("Bob", 30),
            new Person("Charlie", 35)
        };

        Person[] destPeople = new Person[sourcePeople.length];

        // 객체 배열 복사 (얕은 복사)
        System.arraycopy(sourcePeople, 0, destPeople, 0, sourcePeople.length);
    }
}
객체 배열을 복사할 때는 참조만 복사되는 얕은 복사(shallow copy)가 발생합니다. 즉, 원본 배열과 대상 배열의 각 요소는 동일한 객체를 참조합니다.

#5. 성능 분석과 다른 복사 방법 비교
Java에서 배열을 복사하는 방법은 여러 가지가 있습니다. 각 방법의 성능을 비교해보겠습니다.
1) 배열 복사 방법들
System.arraycopy(): 네이티브 메서드로 가장 빠른 성능 제공
Arrays.copyOf(): 내부적으로 System.arraycopy 호출, 새 배열 생성
Arrays.copyOfRange(): 부분 배열 복사, 내부적으로 System.arraycopy 사용
clone(): 배열의 복제본 생성, 새 배열 반환
반복문을 사용한 수동 복사: 요소별로 직접 복사
.....
2) 성능 비교 결과
실행 환경에 따라 결과가 다를 수 있지만, 일반적으로 다음과 같은 성능 순서를 보입니다.
System.arraycopy(): 가장 빠름 (네이티브 구현)
clone(): System.arraycopy보다 약간 느림
Arrays.copyOf(): System.arraycopy를 내부적으로 사용하지만 새 배열 생성 오버헤드 있음
Arrays.copyOfRange(): copyOf와 유사하지만 범위 계산 오버헤드 추가
수동 반복문: 가장 느림 (JVM 최적화 부족)
배열 크기가 클수록 System.arraycopy의 성능 이점이 더 두드러집니다.
.....
3) 주의사항
(1) 타입 호환성
원본 배열과 대상 배열은 타입이 호환되어야 합니다. 예를 들어, int[] 배열에서 double[] 배열로 직접 복사할 수 없습니다.
int[] sourceInts = {1, 2, 3};
double[] destDoubles = new double[3];

// 오류 발생: ArrayStoreException
System.arraycopy(sourceInts, 0, destDoubles, 0, 3);
(2) 배열 범위 문제
배열 범위를 벗어나는 복사 시도는 IndexOutOfBoundsException을 발생시킵니다.
int[] source = {1, 2, 3, 4, 5};
int[] dest = new int[3];

// 오류 발생: 원본 배열 크기(5)가 대상 배열 크기(3)보다 큼
System.arraycopy(source, 0, dest, 0, 5);
(3) null 배열 처리
원본 또는 대상 배열이 null인 경우 NullPointerException이 발생합니다.
int[] source = {1, 2, 3};
int[] dest = null;

// 오류 발생: NullPointerException
System.arraycopy(source, 0, dest, 0, 3);

마무리
이 글에서는 Java의 System.arraycopy 메서드에 대해 상세히 알아보았습니다. 기본 사용법부터 성능 분석, 다양한 예제까지 살펴보았습니다.
System.arraycopy는 Java의 가장 기본적인 배열 조작 도구 중 하나이면서도, 최적화된 성능을 제공하는 강력한 메서드입니다. 특히 대용량 데이터를 다루거나 성능에 민감한 애플리케이션에서는 이 메서드의 특성을 잘 이해하고 활용하는 것이 중요합니다.
네이티브 메서드로 구현되어 JVM 수준의 최적화를 제공하며, 다양한 데이터 타입을 지원하고 부분 복사가 가능한 점이 큰 장점입니다. 다만 타입 호환성, 배열 범위, null 처리 등의 주의사항을 반드시 숙지하고 사용해야 합니다.
긴 글 읽어주셔서 감사합니다.

끝.
반응형