1. 배열 할당의 상한
Java의 배열의 크기는 int 유형을 배열 첨자로 사용하기 때문에 제한됩니다. 즉, 정수의 크기를 초과하는 배열을 신청할 수 없습니다 .max_value (2^31-1). 그렇다고 메모리 응용 프로그램의 상한이 2G라는 것을 의미하지는 않습니다. 더 큰 유형의 배열을 신청할 수 있습니다. 예를 들어:
코드 사본은 다음과 같습니다.
최종 long [] ar = new long [integer.max_value];
이것은 16g -8 바이트를 할당합니다. 설정 한 -xmx 매개 변수가 충분히 크면 공간의 50% 이상을 유지해야합니다. 즉, 메모리를 할당해야합니다. 단지 일반적인 규칙이며, 특정 할당은 실제 상황에 따라 다릅니다).
불행하게도, Java에서는 배열 요소의 유형 제한으로 인해 메모리를 작동하는 것이 더 번거 롭습니다. 작동 배열과 관련하여 바이 테 버퍼는 가장 유용한 클래스 여야하며, 이는 다른 Java 유형을 읽고 쓰는 방법을 제공해야합니다. 그 단점은 대상 배열 유형이 바이트 [] 여야한다는 것입니다. 즉, 할당 할당 된 최대 메모리 캐시는 2G 일 수 있습니다.
2. 모든 배열을 바이트 어레이로 사용하여 작동합니다
2G 메모리가 지금 우리에게는 충분하지 않다고 가정하면 16G라면 괜찮습니다. 우리는 Long []를 할당했지만 바이트 배열로 작동하고 싶습니다. Java에서는 C 프로그래머 -Sun.misc.unsafe에게 도움을 요청해야합니다. 이 클래스에는 getn (오브젝트, 오프셋)이 있습니다 Putn (Object, Offset, value) 메소드는 객체의 오프셋 위치에 값을 작성하는 것입니다.
불행히도 이러한 방법은 특정 유형의 값을 얻거나 설정할 수 있습니다. 배열에서 데이터를 복사하면 다른 안전하지 않은, copymemory (srcobject, srcoffset, destobject, destoffet, count)가 필요합니다. 이것은 System.arrayCopy와 유사하게 작동하지만 배열 요소가 아닌 바이트를 복사합니다.
Sun.Misc.unsafe를 통해 배열의 데이터에 액세스하려면 두 가지가 필요합니다.
1. 배열 객체의 데이터 오프셋
2. 배열 데이터에서 복사 된 요소의 오프셋
다른 Java 객체와 마찬가지로 배열에는 실제 데이터 앞에 저장된 객체 헤더가 있습니다. 이 헤더의 길이는 안전하지 않은.arraybaseoffset (t []. class) 메소드에 의해 얻을 수 있으며, 여기서 t는 배열 요소의 유형입니다. 배열 요소의 크기는 안전하지 않은.arrayindexscale (t []. class) 메소드를 통해 얻을 수 있습니다. 즉, T 형의 N 번째 요소에 액세스하려면 오프셋 오프셋이 ArrayOffset+N*ArrayScale이어야합니다.
간단한 예를 봅시다. 긴 배열을 할당하고 그 안에 몇 바이트를 업데이트합니다. We update the last element to -1 (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF), and then clear all bytes of this element one by one.
코드 사본은 다음과 같습니다.
최종 long [] ar = 새로운 긴 [1000];
최종 int index = ar.length -1;
ar [index] = -1;
System.out.println ( "change 이전 =" + long.tohexstring (ar [index]));
for (long i = 0; i <8; ++ i)
{
insafe.putbyte (ar, longarrayoffset + 8l * index + i, (byte) 0);
System.out.println ( "변경 후 : i =" + i + ", val =" + long.tohexstring (ar [index]);
}
위의 예제를 실행하려면 다음 정적 코드 블록을 테스트 클래스에 추가해야합니다.
코드 사본은 다음과 같습니다.
개인 정적 최종 최종 안전하지 않은 안전하지 않은;
공전
{
노력하다
{
필드 필드 = unsafe.class.getDeclaredfield ( "Theunsafe");
field.setAccessible (true);
안전하지 않은 = (안전하지 않은) field.get (null);
}
캐치 (예외 E)
{
새로운 runtimeexception (e)을 던지십시오.
}
}
개인 정적 최종 Long LongarrayOffset = unsafe.arraybaseoffset (long []. class);
출력 결과는 다음과 같습니다.
코드 사본은 다음과 같습니다.
변경하기 전에 = fffffffffffffffffff
변경 후 : i = 0, val = ffffffffffffff00
변경 후 : i = 1, val = fffffffffffff0000
변경 후 : i = 2, val = ffffffffff000000
변경 후 : i = 3, val = ffffffff00000000
변경 후 : i = 4, val = ffffff00000000000
변경 후 : i = 5, val = ffff0000000000000
변경 후 : i = 6, val = ff000000000000000
변경 후 : i = 7, val = 0
3. Sun.Misc.unsafe의 메모리 할당
위에서 언급했듯이 순수한 Java에서 할당 할 수있는 메모리 크기는 제한적입니다. 이 제한은 Java의 초기 버전으로 설정되었으며 당시 사람들은 이와 같은 여러 g의 메모리를 공유하지 않았습니다. 그러나 이제는 빅 데이터의 시대이며 더 많은 기억이 필요합니다. Java에는 더 많은 기억을 얻는 두 가지 방법이 있습니다.
1. 많은 작은 메모리 덩어리를 할당 한 다음 논리적으로 연속적인 큰 메모리 덩어리로 사용하십시오.
2. Sun.Misc.unsafe.allcatememory (Long)를 사용하여 메모리를 할당하십시오.
첫 번째 방법은 알고리즘의 관점에서 조금 더 흥미 롭기 때문에 두 번째 방법을 살펴 보겠습니다.
Sun.misc.unsafe는 메모리를 할당, 재 할당 및 해제하는 일련의 방법을 제공합니다. C의 Malloc/Free Method와 매우 유사합니다.
1. Long Insafe.allocatememory (긴 크기)-메모리 공간을 할당하십시오. 이 메모리에는 정크 데이터가 포함될 수 있습니다 (자동으로 지우지 않음). 할당이 실패하면 java.lang.outofMemoryError를 제외하고는 발생합니다. 0이 아닌 메모리 주소를 반환합니다 (아래 설명 참조).
2.unsafe.reallocatememory (긴 주소, 긴 크기)-메모리 조각을 Realloce 및 이전 메모리 버퍼 (주소가 가리키는)에서 새로 할당 된 메모리 블록에서 데이터를 복사합니다. 주소가 0 인 경우이 방법은 Allocatememory와 동일한 효과를 갖습니다. 새 메모리 버퍼의 주소를 반환합니다.
3.unsafe.freememory (긴 주소)-이전 두 가지 방법에 의해 생성 된 메모리 버퍼가 없습니다. 주소가 0이면 아무것도하지 않습니다.
이러한 방법으로 할당 된 메모리는 단일 레지스터 주소라는 모드에서 사용해야합니다. 안전하지 않은 것은 하나의 주소 매개 변수 만 허용하는 일련의 메소드를 제공합니다 (듀얼 레지스터 모드와 달리 객체 및 오프셋 오프셋이 필요함). 이러한 방식으로 할당 된 메모리는 -xmx의 Java 매개 변수에서 구성하는 것보다 클 수 있습니다.
참고 : 안전하지 않은 상태에서 할당 된 메모리는 쓰레기를 수집 할 수 없습니다. 당신은 그것을 정상적인 자원으로 취급하고 직접 관리해야합니다.
다음은 미지의 예제입니다. Allocatememory는 메모리를 할당하며 전체 메모리 버퍼를 읽을 수 있고 쓰기 쉬운 지 확인합니다.
코드 사본은 다음과 같습니다.
최종 int size = integer.max_value / 2;
최종 Long Addr = 안전하지 않은 Allocatememory (크기);
노력하다
{
System.out.println ( "안전하지 않은 주소 =" + addr);
for (int i = 0; i <size; ++ i)
{
insafe.putbyte (addr + i, (byte) 123);
if (unsafe.getByte (addr + i)! = 123)
System.out.println ( "오프셋에서 실패 =" + i);
}
}
마지막으로
{
안전하지 않은 .Freememory (addr);
}
보시다시피, Sun.Misc.unsafe를 사용하면 매우 일반적인 메모리 액세스 코드를 작성할 수 있습니다. Java에 어떤 종류의 메모리가 할당 되더라도 모든 유형의 데이터를 읽고 쓸 수 있습니다.