데이터 행 더미가있는 CSV 파일을 읽는 응용 프로그램이 있습니다. 사용자에게 데이터 유형에 따라 행 수에 대한 요약을 제공하지만 너무 많은 행의 데이터를 읽지 않아서 OutOfMemoryError
s가 발생하지 않도록하고 싶습니다 . 각 행은 객체로 변환됩니다. 프로그래밍 방식으로 해당 객체의 크기를 찾는 쉬운 방법이 있습니까? 큰 기본 유형과 객체 참조가 얼마나 큰지를 정의하는 참조가 VM
있습니까?
지금은 최대 32,000 행 을 읽는 코드가 있지만 32MB 의 메모리를 사용할 때까지 가능한 한 많은 행을 읽는 코드를 갖고 싶습니다 . 어쩌면 그것은 다른 질문 일지 모르지만 여전히 알고 싶습니다.
답변
java.lang.instrument 패키지를 사용할 수 있습니다
이 클래스를 컴파일하여 JAR에 넣습니다.
import java.lang.instrument.Instrumentation;
public class ObjectSizeFetcher {
private static Instrumentation instrumentation;
public static void premain(String args, Instrumentation inst) {
instrumentation = inst;
}
public static long getObjectSize(Object o) {
return instrumentation.getObjectSize(o);
}
}
에 다음을 추가하십시오 MANIFEST.MF
.
Premain-Class: ObjectSizeFetcher
getObjectSize를 사용하십시오.
public class C {
private int x;
private int y;
public static void main(String [] args) {
System.out.println(ObjectSizeFetcher.getObjectSize(new C()));
}
}
다음과 같이 호출하십시오.
java -javaagent:ObjectSizeFetcherAgent.jar C
답변
OpenJDK 프로젝트의 일부로 개발 된 도구 인 jol을 사용해야합니다 .
JOL (Java Object Layout)은 JVM에서 객체 레이아웃 구성표를 분석하는 작은 도구 상자입니다. 이러한 도구는 Unsafe, JVMTI 및 SA (Serviceability Agent)를 많이 사용하여 실제 객체 레이아웃, 풋 프린트 및 참조를 해독합니다. 따라서 힙 덤프, 사양 가정 등에 의존하는 다른 도구보다 JOL이 훨씬 정확합니다.
프리미티브, 참조 및 배열 요소의 크기를 얻으려면을 사용하십시오 VMSupport.vmDetails()
. 64 비트 Windows에서 실행중인 Oracle JDK 1.8.0_40 (다음의 모든 예제에 사용)에서이 메소드는 다음을 리턴합니다.
Running 64-bit HotSpot VM.
Using compressed oop with 0-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
ClassLayout.parseClass(Foo.class).toPrintable()
(선택적으로 인스턴스를에 전달)를 사용하여 객체 인스턴스의 얕은 크기를 얻을 수 있습니다 toPrintable
. 이것은 해당 클래스의 단일 인스턴스가 사용하는 공간입니다. 해당 클래스가 참조하는 다른 객체는 포함하지 않습니다. 여기 에는 개체 헤더, 필드 정렬 및 패딩에 대한 VM 오버 헤드 가 포함됩니다. 의 경우 java.util.regex.Pattern
:
java.util.regex.Pattern object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (0000 0001 0000 0000 0000 0000 0000 0000)
4 4 (object header) 00 00 00 00 (0000 0000 0000 0000 0000 0000 0000 0000)
8 4 (object header) cb cf 00 20 (1100 1011 1100 1111 0000 0000 0010 0000)
12 4 int Pattern.flags 0
16 4 int Pattern.capturingGroupCount 1
20 4 int Pattern.localCount 0
24 4 int Pattern.cursor 48
28 4 int Pattern.patternLength 0
32 1 boolean Pattern.compiled true
33 1 boolean Pattern.hasSupplementary false
34 2 (alignment/padding gap) N/A
36 4 String Pattern.pattern (object)
40 4 String Pattern.normalizedPattern (object)
44 4 Node Pattern.root (object)
48 4 Node Pattern.matchRoot (object)
52 4 int[] Pattern.buffer null
56 4 Map Pattern.namedGroups null
60 4 GroupHead[] Pattern.groupNodes null
64 4 int[] Pattern.temp null
68 4 (loss due to the next object alignment)
Instance size: 72 bytes (reported by Instrumentation API)
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
을 사용하여 객체 인스턴스의 깊은 크기에 대한 요약보기를 얻을 수 있습니다 GraphLayout.parseInstance(obj).toFootprint()
. 물론, 풋 프린트의 일부 오브젝트는 공유 될 수 있으며 (다른 오브젝트에서도 참조 될 수 있음), 해당 오브젝트가 가비지 콜렉션 될 때 재 확보 될 수있는 공간의 초과 근사치입니다. Pattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$")
( 이 답변 에서 가져온) 결과에 대해 jol은 총 1840 바이트의 풋 프린트를보고하며 그 중 72 개만이 Pattern 인스턴스 자체입니다.
java.util.regex.Pattern instance footprint:
COUNT AVG SUM DESCRIPTION
1 112 112 [C
3 272 816 [Z
1 24 24 java.lang.String
1 72 72 java.util.regex.Pattern
9 24 216 java.util.regex.Pattern$1
13 24 312 java.util.regex.Pattern$5
1 16 16 java.util.regex.Pattern$Begin
3 24 72 java.util.regex.Pattern$BitClass
3 32 96 java.util.regex.Pattern$Curly
1 24 24 java.util.regex.Pattern$Dollar
1 16 16 java.util.regex.Pattern$LastNode
1 16 16 java.util.regex.Pattern$Node
2 24 48 java.util.regex.Pattern$Single
40 1840 (total)
대신을 사용 GraphLayout.parseInstance(obj).toPrintable()
하면 jol은 참조하는 각 객체에 대한 주소, 크기, 유형, 값 및 필드 역 참조 경로를 알려줍니다. 진행중인 패턴 예제의 경우 다음을 얻을 수 있습니다. (주소는 실행간에 변경 될 수 있습니다.)
java.util.regex.Pattern object externals:
ADDRESS SIZE TYPE PATH VALUE
d5e5f290 16 java.util.regex.Pattern$Node .root.next.atom.next (object)
d5e5f2a0 120 (something else) (somewhere else) (something else)
d5e5f318 16 java.util.regex.Pattern$LastNode .root.next.next.next.next.next.next.next (object)
d5e5f328 21664 (something else) (somewhere else) (something else)
d5e647c8 24 java.lang.String .pattern (object)
d5e647e0 112 [C .pattern.value [^, [, a, -, z, A, -, Z, 0, -, 9, _, ., +, -, ], +, @, [, a, -, z, A, -, Z, 0, -, 9, -, ], +, \, ., [, a, -, z, A, -, Z, 0, -, 9, -, ., ], +, $]
d5e64850 448 (something else) (somewhere else) (something else)
d5e64a10 72 java.util.regex.Pattern (object)
d5e64a58 416 (something else) (somewhere else) (something else)
d5e64bf8 16 java.util.regex.Pattern$Begin .root (object)
d5e64c08 24 java.util.regex.Pattern$BitClass .root.next.atom.val$rhs (object)
d5e64c20 272 [Z .root.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
d5e64d30 24 java.util.regex.Pattern$1 .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
d5e64d48 24 java.util.regex.Pattern$1 .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
d5e64d60 24 java.util.regex.Pattern$5 .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
d5e64d78 24 java.util.regex.Pattern$1 .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
d5e64d90 24 java.util.regex.Pattern$5 .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
d5e64da8 24 java.util.regex.Pattern$5 .root.next.atom.val$lhs.val$lhs.val$lhs (object)
d5e64dc0 24 java.util.regex.Pattern$5 .root.next.atom.val$lhs.val$lhs (object)
d5e64dd8 24 java.util.regex.Pattern$5 .root.next.atom.val$lhs (object)
d5e64df0 24 java.util.regex.Pattern$5 .root.next.atom (object)
d5e64e08 32 java.util.regex.Pattern$Curly .root.next (object)
d5e64e28 24 java.util.regex.Pattern$Single .root.next.next (object)
d5e64e40 24 java.util.regex.Pattern$BitClass .root.next.next.next.atom.val$rhs (object)
d5e64e58 272 [Z .root.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
d5e64f68 24 java.util.regex.Pattern$1 .root.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
d5e64f80 24 java.util.regex.Pattern$1 .root.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
d5e64f98 24 java.util.regex.Pattern$5 .root.next.next.next.atom.val$lhs.val$lhs (object)
d5e64fb0 24 java.util.regex.Pattern$1 .root.next.next.next.atom.val$lhs.val$rhs (object)
d5e64fc8 24 java.util.regex.Pattern$5 .root.next.next.next.atom.val$lhs (object)
d5e64fe0 24 java.util.regex.Pattern$5 .root.next.next.next.atom (object)
d5e64ff8 32 java.util.regex.Pattern$Curly .root.next.next.next (object)
d5e65018 24 java.util.regex.Pattern$Single .root.next.next.next.next (object)
d5e65030 24 java.util.regex.Pattern$BitClass .root.next.next.next.next.next.atom.val$rhs (object)
d5e65048 272 [Z .root.next.next.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
d5e65158 24 java.util.regex.Pattern$1 .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
d5e65170 24 java.util.regex.Pattern$1 .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$rhs (object)
d5e65188 24 java.util.regex.Pattern$5 .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
d5e651a0 24 java.util.regex.Pattern$1 .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
d5e651b8 24 java.util.regex.Pattern$5 .root.next.next.next.next.next.atom.val$lhs.val$lhs (object)
d5e651d0 24 java.util.regex.Pattern$5 .root.next.next.next.next.next.atom.val$lhs (object)
d5e651e8 24 java.util.regex.Pattern$5 .root.next.next.next.next.next.atom (object)
d5e65200 32 java.util.regex.Pattern$Curly .root.next.next.next.next.next (object)
d5e65220 120 (something else) (somewhere else) (something else)
d5e65298 24 java.util.regex.Pattern$Dollar .root.next.next.next.next.next.next (object)
“(something else)”항목 은 힙에서이 객체 그래프의 일부가 아닌 다른 객체를 설명합니다 .
최고의 jol 문서는 jol 저장소 의 jol 샘플 입니다. 샘플은 일반적인 jol 조작을 보여주고 jol을 사용하여 VM 및 가비지 콜렉터 내부를 분석하는 방법을 보여줍니다.
답변
실수로 jdk에 이미있는 자바 클래스 “jdk.nashorn.internal.ir.debug.ObjectSizeCalculator”를 발견했습니다. 이는 사용하기 쉽고 객체의 크기를 결정하는 데 매우 유용한 것으로 보입니다.
System.out.println(ObjectSizeCalculator.getObjectSize(new gnu.trove.map.hash.TObjectIntHashMap<String>(12000, 0.6f, -1)));
System.out.println(ObjectSizeCalculator.getObjectSize(new HashMap<String, Integer>(100000)));
System.out.println(ObjectSizeCalculator.getObjectSize(3));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[]{1, 2, 3, 4, 5, 6, 7 }));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[100]));
결과 :
164192
48
16
48
416
답변
몇 년 전 Javaworld는 복합 및 잠재적으로 중첩 된 Java 객체의 크기를 결정하는 데 관한 기사를 가지고 있었으며 기본적으로 Java 에서 sizeof () 구현을 작성하는 과정을 안내합니다. 이 접근 방식은 기본적으로 사람들이 기본적으로 프리미티브 및 일반적인 Java 객체의 크기를 식별 한 다음 전체 크기를 계산하기 위해 객체 그래프를 재귀 적으로 걷는 방법에 해당 지식을 적용하는 다른 작업을 기반으로합니다.
클래스의 무대 뒤에서 일어나는 일 때문에 항상 네이티브 C 구현보다 다소 덜 정확하지만 좋은 지표가되어야합니다.
또는 sizeof () 구현으로 Java5 라이브러리를 제공하는 sizeof 라는 적절한 SourceForge 프로젝트 .
PS 직렬화 방법을 사용하지 마십시오. 직렬화 된 객체의 크기와 라이브시 소비하는 메모리 양 사이에는 상관이 없습니다.
답변
먼저 “객체의 크기”는 Java에서 잘 정의 된 개념이 아닙니다. 멤버, 오브젝트 및 참조하는 모든 오브젝트 (참조 그래프)만으로 오브젝트 자체를 의미 할 수 있습니다. 메모리의 크기 또는 디스크의 크기를 의미 할 수 있습니다. 그리고 JVM은 문자열과 같은 것을 최적화 할 수 있습니다.
따라서 올바른 올바른 방법은 프로파일 러 ( YouKit 사용 )로 JVM에 요청 하는 것입니다.
그러나 위의 설명에서 각 행이 독립적이며 큰 종속성 트리가없는 것처럼 들리므로 직렬화 방법은 대부분의 JVM에서 좋은 근사치 일 것입니다. 가장 쉬운 방법은 다음과 같습니다.
Serializable ser;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(ser);
oos.close();
return baos.size();
당신은 일반적인 참조가 개체가있는 경우이 것을 기억 하지 않습니다 정확한 결과를 제공하고, 직렬화의 크기는 항상 메모리 크기와 일치하지 않습니다,하지만 좋은 근사이다. ByteArrayOutputStream 크기를 적절한 값으로 초기화하면 코드가 조금 더 효율적입니다.
답변
JVM에서 사용되는 메모리 양과 사용 가능한 양을 알고 싶다면 다음과 같이 시도하십시오.
// Get current size of heap in bytes
long heapSize = Runtime.getRuntime().totalMemory();
// Get maximum size of heap in bytes. The heap cannot grow beyond this size.
// Any attempt will result in an OutOfMemoryException.
long heapMaxSize = Runtime.getRuntime().maxMemory();
// Get amount of free memory within the heap in bytes. This size will increase
// after garbage collection and decrease as new objects are created.
long heapFreeSize = Runtime.getRuntime().freeMemory();
편집 : 나는 질문 작성자가 “32MB의 메모리를 사용할 때까지 가능한 한 많은 행을 읽습니다.”를 처리하는 논리를 갖고 싶다고 말했기 때문에 이것이 도움이 될 것이라고 생각했습니다.
답변
트위터에서 일할 때 깊은 물체 크기를 계산하는 유틸리티를 작성했습니다. 서로 다른 메모리 모델 (32 비트, 압축 된 oop, 64 비트), 패딩, 서브 클래스 패딩을 고려하여 순환 데이터 구조 및 배열에서 올바르게 작동합니다. 이 하나의 .java 파일을 컴파일하면됩니다. 외부 종속성이 없습니다.
