Java에서 메모리 할당의 몇 가지 방법

5112 단어 Java메모리 할당
1. 수조 분배의 상한선
Java에서 배열의 크기는 제한됩니다. 왜냐하면 int 형식을 배열 아래 표식으로 사용하기 때문입니다.이것은 당신이 Integer를 초과할 수 없다는 것을 의미한다.MAX_VALUE(2^31-1) 크기의 배열입니다.이것은 네가 메모리를 신청하는 상한선이 2G라는 것을 말하는 것이 아니다.너는 좀 큰 유형의 그룹을 신청할 수 있다.예:

final long[] ar = new long[ Integer.MAX_VALUE ];
이것은 16G-8바이트를 분배합니다. 만약 당신이 설정한 -Xmx 파라미터가 충분하다면 (보통 당신의 더미는 적어도 50% 이상의 공간을 보존해야 합니다. 즉, 16G의 메모리를 분배하려면 -Xmx24G로 설정해야 합니다. 이것은 일반적인 규칙일 뿐입니다. 구체적인 분배가 얼마나 큰지는 실제 상황을 보아야 합니다.)
불행하게도 자바에서는 그룹 요소의 유형 제한으로 인해 메모리를 조작하는 것이 비교적 번거롭다.조작 수조에 있어서 ByteBuffer는 가장 유용한 클래스일 것이다. 이것은 서로 다른 자바 형식을 읽고 쓰는 방법을 제공한다.그것의 단점은 목표 그룹 형식은byte[]이어야 한다는 것이다. 즉, 할당된 메모리 캐시는 최대 2G밖에 안 된다는 것이다.
2. 모든 수조를 byte 수조로 조작한다
현재 2G 메모리가 우리에게 매우 부족하다고 가정하면 16G라면 그런대로 괜찮다.우리는 이미long[]을 분배했지만, 그것을byte수조로 삼아 조작하기를 희망합니다.자바에서 우리는 C 프로그래머의 좋은 조수를 구해야 한다.misc.Unsafe.이 클래스는 두 가지 방법이 있습니다. getN(object,offset). 이 방법은 object 편이량이 offset인 위치에서 지정한 형식의 값을 가져와 되돌려줍니다. N은 여기서 되돌려줄 값을 나타내는 형식이고,putN(Object,offset,value) 방법은 Object의 offset의 그 위치에 값을 쓰는 것입니다.
불행하게도, 이 방법들은 어떤 종류의 값만 얻거나 설정할 수 있다.만약 수조에서 데이터를 복사한다면, unsafe의 또 다른 방법이 필요합니다. copy Memory (src Object, src Offset,dest Object,dest Offet,count).이것과 시스템.arraycopy의 작업 방식은 유사하지만, 수조 요소가 아닌 바이트를 복사합니다.
해를 통과하고 싶어요.misc.Unsafe는 그룹의 데이터에 접근하기 위해 두 가지를 필요로 합니다.
1. 그룹 대상의 데이터 편이량 2.복사된 요소는 그룹 데이터의 편이량인 Arrays와 Java의 다른 대상과 마찬가지로 하나의 대상 헤더가 있는데 이것은 실제 데이터 앞에 저장된 것이다.이 머리의 길이는 unsafe를 통과할 수 있다.arrayBaseOffset(T[].class) 방법으로 얻을 수 있습니다. 여기 T는 그룹 요소의 유형입니다.그룹 원소의 크기는 unsafe를 통과할 수 있습니다.arrayIndexScale(T[].class) 메서드를 사용할 수 있습니다.즉, T 형식의 N번째 요소에 접근하려면 오프셋 오프셋은array Offset + N*arrayscale이어야 합니다.
우리 간단한 예를 하나 쓰자.우리는 롱 그룹을 분배한 후에 그 안의 몇 바이트를 업데이트합니다.우리는 마지막 원소를 -1(16진법이면 0xFFFFFF)로 업데이트하고 이 원소의 모든 바이트를 하나씩 제거합니다..

final long[] ar = new long[ 1000 ];
final int index = ar.length - 1;
ar[ index ] = -1; //FFFF FFFF FFFF FFFF

System.out.println( "Before change = " + Long.toHexString( ar[ index ] ));

for ( long i = 0; i < 8; ++i )
{
    unsafe.putByte( ar, longArrayOffset + 8L * index + i, (byte) 0);
    System.out.println( "After change: i = " + i + ", val = "  +  Long.toHexString( ar[ index ] ));
}

위의 예를 실행하려면 테스트 클래스에 아래의 정적 코드 블록을 추가해야 합니다

private static final Unsafe unsafe;
static
{
    try
    {
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        unsafe = (Unsafe)field.get(null);
    }
    catch (Exception e)
    {
        throw new RuntimeException(e);
    }
}
private static final long longArrayOffset = unsafe.arrayBaseOffset(long[].class);출력의 결과는:

Before change = ffffffffffffffff
After change: i = 0, val = ffffffffffffff00
After change: i = 1, val = ffffffffffff0000
After change: i = 2, val = ffffffffff000000
After change: i = 3, val = ffffffff00000000
After change: i = 4, val = ffffff0000000000
After change: i = 5, val = ffff000000000000
After change: i = 6, val = ff00000000000000
After change: i = 7, val = 0
3. 썬.misc.Unsafe 메모리 할당
위에서 말했듯이 순수 자바에서 우리가 분배할 수 있는 메모리 크기는 유한하다.이 제한은 자바의 최초 버전에서 이미 정해졌는데, 그때는 사람들이 몇 개의 G를 분배하는 메모리가 어떤 상황인지 감히 닮지 못했다.그러나 지금은 이미 빅데이터의 시대이기 때문에 우리는 더 많은 메모리를 필요로 한다.Java에서 더 많은 메모리를 얻으려면 두 가지 방법이 있습니다.
1. 많은 작은 블록의 메모리를 분배하고 논리적으로 그것들을 연속적인 큰 메모리로 사용한다.2. 태양을 사용한다.misc.Unsafe.메모리 할당을 위해 allcateMemory(long)를 사용합니다.첫 번째 방법은 알고리즘의 측면에서 볼 때 좀 재미있을 뿐이니 두 번째 방법을 살펴보자.
sun.misc.Unsafe는 메모리 할당, 재할당, 방출을 위한 방법을 제공합니다.그것들은 C의malloc/free 방법과 매우 비슷하다.
1.long Unsafe.allocateMemory (long size) - 메모리 공간을 분배합니다.이 메모리에는 쓰레기 데이터가 포함될 수 있다.분배가 실패하면java를 던집니다.lang.OutOfMemoryError의 예외입니다.0이 아닌 메모리 주소를 되돌려줍니다. (아래 설명 참조)2.Unsafe.reallocate Memory (long address, long size) - 메모리를 다시 분배하고 데이터를 낡은 메모리 버퍼 (address가 가리키는 곳) 에서 새로 분배된 메모리 블록으로 복사합니다.만약 주소가 0이라면, 이 방법은 allocateMemory의 효과와 같다.새 메모리 버퍼의 주소를 되돌려줍니다.3.Unsafe.free Memory (long address) - 앞의 두 가지 방법으로 생성된 메모리 버퍼를 방출합니다.address가 0이면 아무것도 안 해요.
이러한 방법으로 분배된 메모리는 단일 레지스터 주소라고 불리는 모드에서 사용해야 한다. Unsafe는 하나의 주소 매개 변수만 받아들일 수 있는 방법을 제공한다. (이중 레지스터 모드와 달리 Object와 편이량 offset이 필요하다.)이런 방식으로 분배된 메모리는 당신이 -Xmx의 자바 매개 변수에 설정한 것보다 더 크다.
주의: Unsafe가 할당한 메모리는 쓰레기 수거를 할 수 없습니다.너는 그것을 정상적인 자원으로 생각하고 스스로 관리해야 한다.
다음은 Unsafe를 사용합니다.allocateMemory 할당 메모리의 한 예이며, 전체 메모리 버퍼가 읽을 수 있는지 확인합니다

final int size = Integer.MAX_VALUE / 2;
final long addr = unsafe.allocateMemory( size );
try
{
    System.out.println( "Unsafe address = " + addr );
    for ( int i = 0; i < size; ++i )
    {
        unsafe.putByte( addr + i, (byte) 123);
        if ( unsafe.getByte( addr + i ) != 123 )
            System.out.println( "Failed at offset = " + i );
    }
}
finally
{
    unsafe.freeMemory( addr );
}
보시다시피 선을 사용하세요.misc.Unsafe는 매우 일반적인 메모리 접근 코드를 쓸 수 있습니다. 자바에서 분배된 어떤 메모리든지 임의의 형식의 데이터를 읽을 수 있습니다.

좋은 웹페이지 즐겨찾기