Java 객체는 얼마나 많은 메모리를 차지합니까?
최근에 "Java Virtual Machine에 대한 심층적 이해"를 읽으면서 Java 객체의 메모리 레이아웃에 대해 더 잘 이해하게 되었습니다. 그래서 자연스럽게 Java가 메모리를 얼마나 사용하는지에 대한 매우 일반적인 질문이 떠올랐습니다. 객체 점유?
인터넷에서 아주 잘 이야기하는 블로그를 찾았습니다: http://yueyemaitian.iteeye.com/blog/2033046 거기에서 제공되는 수업도 매우 실용적입니다:
import java.lang.instrument.Instrumentation; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayDeque; import java.util.Deque; import java.util.HashSet; import java.util.Set; /** * 对象占用字节大小工具类 * * @author tianmai.fh * @date 2014-03-18 11:29 */ public class SizeOfObject { static Instrumentation inst; public static void premain(String args, Instrumentation instP) { inst = instP; } /** * 直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、<br></br> * 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;<br></br> * 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小 <br></br> * * @param obj * @return */ public static long sizeOf(Object obj) { return inst.getObjectSize(obj); } /** * 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小 * * @param objP * @return * @throws IllegalAccessException */ public static long fullSizeOf(Object objP) throws IllegalAccessException { Set<Object> visited = new HashSet<Object>(); Deque<Object> toBeQueue = new ArrayDeque<Object>(); toBeQueue.add(objP); long size = 0L; while (toBeQueue.size() > 0) { Object obj = toBeQueue.poll(); //sizeOf的时候已经计基本类型和引用的长度,包括数组 size += skipObject(visited, obj) ? 0L : sizeOf(obj); Class<?> tmpObjClass = obj.getClass(); if (tmpObjClass.isArray()) { //[I , [F 基本类型名字长度是2 if (tmpObjClass.getName().length() > 2) { for (int i = 0, len = Array.getLength(obj); i < len; i++) { Object tmp = Array.get(obj, i); if (tmp != null) { //非基本类型需要深度遍历其对象 toBeQueue.add(Array.get(obj, i)); } } } } else { while (tmpObjClass != null) { Field[] fields = tmpObjClass.getDeclaredFields(); for (Field field : fields) { if (Modifier.isStatic(field.getModifiers()) //静态不计 || field.getType().isPrimitive()) { //基本类型不重复计 continue; } field.setAccessible(true); Object fieldValue = field.get(obj); if (fieldValue == null) { continue; } toBeQueue.add(fieldValue); } tmpObjClass = tmpObjClass.getSuperclass(); } } } return size; } /** * String.intern的对象不计;计算过的不计,也避免死循环 * * @param visited * @param obj * @return */ static boolean skipObject(Set<Object> visited, Object obj) { if (obj instanceof String && obj == ((String) obj).intern()) { return true; } return visited.contains(obj); } }
이 코드를 사용하여 읽고 확인할 수 있습니다. 참고로 이 프로그램을 실행하려면 javaagent를 통해 Instrumentation을 주입해야 합니다. 자세한 내용은 원본 블로그를 참조하세요. 오늘은 Java 객체가 차지하는 바이트 수를 수동으로 계산하는 기본 규칙을 주로 요약합니다. 기본 기술로 get√가 저와 같은 Java 초보자에게 도움이 되기를 바랍니다.
소개에 앞서 Java 객체의 메모리 레이아웃인 객체 헤더(Header), 인스턴스 데이터(Instance Data) 및 정렬 패딩(Padding)을 간략하게 검토하겠습니다. 메모 . 또한 내 환경은 HotSpot 가상 머신과 64비트 Windows이므로 환경에 따라 결과가 다를 수 있습니다.
이제 다음 텍스트를 입력하십시오.
개체 헤더
개체 헤더는 32비트 시스템에서는 8바이트, 64비트 시스템에서는 16바이트를 차지합니다.
인스턴스 데이터
기본형의 메모리 사용량은 다음과 같습니다.
기본형 메모리 필요량(바이트)
부울 1
바이트 1
짧은 2
문자 2
int 4
float 4
long 8
double 8
참조 유형은 32비트 시스템에서 각각 4바이트, 64비트 시스템에서 각각 8바이트를 차지합니다.
정렬 패딩
HotSpot의 정렬은 8바이트 정렬입니다.
(객체 헤더 + 인스턴스 데이터 + 패딩) % 8은 0 및 0과 같습니다. <= 패딩 < ;
포인터 압축
객체가 차지하는 메모리 크기는 VM 매개변수 UseCompressedOops의 영향을 받습니다.
1) 개체 헤더에 미치는 영향
켜기(-XX:+UseCompressedOops) 개체 헤더 크기는 12바이트(64비트 시스템)입니다.
static class A { int a; }
객체 A가 차지하는 메모리:
포인터 압축 끄기: 16+4=20은 8의 배수가 아니므로 +padding/4= 24
포인터 압축을 켭니다. 12+4=16은 이미 8의 배수이므로 패딩이 필요하지 않습니다.
2) 참조 유형에 미치는 영향
64비트 시스템에서 참조 유형은 8바이트를 차지하며, 포인터 압축 시 4바이트를 차지합니다.
static class B2 { int b2a; Integer b2b; }
B2 객체 메모리 사용량:
포인터 압축 끄기: 16+4+8=28은 8의 배수가 아니므로 +padding/4 =32
포인터 압축 활성화: 12+4+4=20은 8의 배수가 아니므로 +padding/4=24
배열 개체
64비트 시스템에서 배열 개체의 개체 헤더는 24바이트를 차지하며, 압축이 활성화된 후에는 16바이트를 차지합니다. 일반 객체에 비해 메모리를 더 많이 차지하는 이유는 배열의 길이를 저장하기 위해 추가 공간이 필요하기 때문입니다.
먼저 new Integer[0]이 차지하는 메모리 크기를 고려하세요. 길이는 객체 헤더의 크기인 0입니다.
압축이 켜지지 않음: 24bytes
압축을 켠 후: 16바이트
그런 다음 새 정수를 계산합니다. 1], new Integer[2 ], new Integer[3] 및 new Integer[4]는 쉽습니다.
압축 없음:
开启压缩:
拿new Integer[3]来具体解释下:
未开启压缩:24(对象头)+8*3=48,不需要padding;
开启压缩:16(对象头)+3*4=28,+padding/4=32,其他依次类推。
自定义类的数组也是一样的,比如:
static class B3 { int a; Integer b; }
new B3[3]占用的内存大小:
未开启压缩:48
开启压缩后:32
复合对象
计算复合对象占用内存的大小其实就是运用上面几条规则,只是麻烦点。
1)对象本身的大小
直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小; 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小。
static class B { int a; int b; } static class C { int ba; B[] as = new B[3]; C() { for (int i = 0; i < as.length; i++) { as[i] = new B(); } } }
未开启压缩:16(对象头)+4(ba)+8(as引用的大小)+padding/4=32
开启压缩:12+4+4+padding/4=24
2)当前对象占用的空间总大小
递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小。
递归计算复合对象占用的内存的时候需要注意的是:对齐填充是以每个对象为单位进行的,看下面这个图就很容易明白。
现在我们来手动计算下C对象占用的全部内存是多少,主要是三部分构成:C对象本身的大小+数组对象的大小+B对象的大小。
未开启压缩:
(16 + 4 + 8+4(padding)) + (24+ 8*3) +(16+8)*3 = 152bytes
开启压缩:
(12 + 4 + 4 +4(padding)) + (16 + 4*3 +4(数组对象padding)) + (12+8+4(B对象padding))*3= 128bytes
大家有兴趣的可以试试。
实际工作中真正需要手动计算对象大小的场景应该很少,但是个人觉得做为基础知识每个Java开发人员都应该了解,另外:对自己写的代码大概占用多少内存,内存中是怎么布局的应该有一个直觉性的认识。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











3일 홈페이지 보도에 따르면 국내 언론 에트뉴스는 어제(현지시간) 삼성전자와 SK하이닉스의 'HBM형' 적층구조 모바일 메모리 제품이 2026년 이후 상용화될 것이라고 보도했다. 소식통에 따르면 두 한국 메모리 거대 기업은 적층형 모바일 메모리를 미래 수익의 중요한 원천으로 여기고 'HBM형 메모리'를 스마트폰, 태블릿, 노트북으로 확장해 엔드사이드 AI에 전력을 공급할 계획이라고 전했다. 이 사이트의 이전 보도에 따르면 삼성전자 제품은 LPWide I/O 메모리라고 하며 SK하이닉스는 이 기술을 VFO라고 부른다. 두 회사는 팬아웃 패키징과 수직 채널을 결합하는 것과 거의 동일한 기술 경로를 사용했습니다. 삼성전자 LPWide I/O 메모리의 비트폭은 512이다.

Java의 난수 생성기 안내. 여기서는 예제를 통해 Java의 함수와 예제를 통해 두 가지 다른 생성기에 대해 설명합니다.

Java의 Weka 가이드. 여기에서는 소개, weka java 사용 방법, 플랫폼 유형 및 장점을 예제와 함께 설명합니다.

Java의 Smith Number 가이드. 여기서는 정의, Java에서 스미스 번호를 확인하는 방법에 대해 논의합니다. 코드 구현의 예.

이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다
