ホームページ Java &#&チュートリアル Java オブジェクトはどれくらいのメモリを占有しますか?

Java オブジェクトはどれくらいのメモリを占有しますか?

Nov 26, 2016 am 11:45 AM
java Javaオブジェクト メモリ

最近、「Java 仮想マシンの詳細」を読んで、Java オブジェクトのメモリ レイアウトについてより深く理解できるようになりました。そこで、Java オブジェクトがどれくらいのメモリを占有するのかという非常に一般的な質問が自然に頭に浮かびました。 ?

インターネット上で非常に優れたブログを見つけました: http://yueyemaitian.iteye.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 を介してインストルメンテーションを挿入する必要があることに注意してください。詳細については、元のブログを参照してください。今日は主に、Java オブジェクトが占有するバイト数を手動で計算するための基本的なルールをまとめます。基本的なスキルとして、私のような Java 初心者に役立つことを願っています。

概要を説明する前に、Java オブジェクトのメモリ レイアウト (ヘッダー、インスタンス データ、パディング) について簡単に説明します。詳細については、私の読書メモを参照してください。さらに、環境によっては結果が異なる場合があります。私の環境は HotSpot 仮想マシンと 64 ビット Windows です。

次にテキストを入力します:

オブジェクトヘッダー

オブジェクトヘッダーは、32 ビット システムでは 8 バイト、64 ビット システムでは 16 バイトを占めます。

Java オブジェクトはどれくらいのメモリを占有しますか?

インスタンスデータ

プリミティブ型のメモリ使用量は以下の通りです:

Primitive Type Memory Required(bytes)

boolean 1

byte 1

short 2

char 2

int 4

float 4

long 8

double 8

参照型は、32 ビット システムではそれぞれ 4 バイト、64 ビット システムではそれぞれ 8 バイトを占有します。

アライメントされたパディング

HotSpotのアライメントは8バイトアライメントです:

(オブジェクトヘッダー + インスタンスデータ + パディング) % 8は0と0に等しい <= パディング < 8

ポインタ圧縮

オブジェクトによって占有されるメモリサイズは VM パラメータ UseCompressedOops の影響を受けます。

1) オブジェクトヘッダーへの影響

(-XX:+UseCompressedOops)をオンにすると、オブジェクトヘッダーのサイズは12バイト(64ビットマシン)になります。

static class A {
        int a;
    }
ログイン後にコピー

オブジェクトのメモリ使用量:

ポインタ圧縮をオフにする: 16+4=20 は 8 の倍数ではないため、+padding/4=24

Java オブジェクトはどれくらいのメモリを占有しますか?

ポインタ圧縮をオンにする: 12+ 4=16 これはすでに 8 の倍数なので、パディングは必要ありません。

Java オブジェクトはどれくらいのメモリを占有しますか?

2)参照型への影響

参照型は64ビットマシンでは8バイトを占有し、ポインタ圧縮をオンにした後は4バイトを占有します。

static class B2 {
        int b2a;
        Integer b2b;
}
ログイン後にコピー

B2 オブジェクトのメモリ使用量:

ポインター圧縮をオフにする: 16+4+8=28 は 8 の倍数ではないため、+padding/4=32

Java オブジェクトはどれくらいのメモリを占有しますか?

ポインター圧縮をオンにする: 12+ 4+4 =20 は 8 の倍数ではないため、+padding/4=24

Java オブジェクトはどれくらいのメモリを占有しますか?

配列オブジェクト

64 ビット マシンでは、配列オブジェクトのオブジェクト ヘッダーは 24 バイトを占有し、次に 16 バイトを占有します圧縮が有効になった後。通常のオブジェクトよりも多くのメモリを消費する理由は、配列の長さを格納するために余分なスペースが必要になるためです。

まず、新しい Integer[0] が占有するメモリ サイズを考慮します。長さは 0、オブジェクト ヘッダーのサイズです:

圧縮なし: 24 バイト

Java オブジェクトはどれくらいのメモリを占有しますか?

圧縮をオンにした後: 16 bytes

Java オブジェクトはどれくらいのメモリを占有しますか?

その後、 new Integer[1]、new Integer[2]、new Integer[3]、new Integer[4] を計算するのは簡単です:

Compression はオンになっていません:

Java オブジェクトはどれくらいのメモリを占有しますか?

  开启压缩:

Java オブジェクトはどれくらいのメモリを占有しますか?

  拿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)当前对象占用的空间总大小

  递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小。

  递归计算复合对象占用的内存的时候需要注意的是:对齐填充是以每个对象为单位进行的,看下面这个图就很容易明白。

Java オブジェクトはどれくらいのメモリを占有しますか?

现在我们来手动计算下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开发人员都应该了解,另外:对自己写的代码大概占用多少内存,内存中是怎么布局的应该有一个直觉性的认识。


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの平方根 Javaの平方根 Aug 30, 2024 pm 04:26 PM

Java の平方根のガイド。ここでは、Java で平方根がどのように機能するかを、例とそのコード実装をそれぞれ示して説明します。

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

関係者によると、サムスン電子とSKハイニックスは2026年以降に積層型モバイルメモリを商品化する予定 関係者によると、サムスン電子とSKハイニックスは2026年以降に積層型モバイルメモリを商品化する予定 Sep 03, 2024 pm 02:15 PM

9月3日の当ウェブサイトのニュースによると、韓国メディアetnewsは昨日(現地時間)、サムスン電子とSKハイニックスの「HBM類似」積層構造モバイルメモリ製品が2026年以降に商品化されると報じた。関係者によると、韓国のメモリ大手2社はスタック型モバイルメモリを将来の重要な収益源と考えており、エンドサイドAIに電力を供給するために「HBMのようなメモリ」をスマートフォン、タブレット、ラップトップに拡張する計画だという。このサイトの以前のレポートによると、Samsung Electronics の製品は LPwide I/O メモリと呼ばれ、SK Hynix はこのテクノロジーを VFO と呼んでいます。両社はほぼ同じ技術的ルート、つまりファンアウト パッケージングと垂直チャネルを組み合わせたものを使用しました。 Samsung Electronics の LPwide I/O メモリのビット幅は 512

Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

See all articles