你知道一个Java对象到底占多少内存吗?

美团面试:如何计算一个对象在内存中占多少个字节? 在分配对象的时候会有一些基本的规则,我们可以根据一些规则大致能判断出来对象大小。 阅读详情

Java虚拟机如何在运行时知道每一块内存存储数据的类型的?

  • 知道Java中int占4个字节,short占2个字节,引用类型在64位机器上占4个字节(不开启指针压缩是8个字节,指针压缩是默认开启的),那JVM如何在运行时知道某一块内存存的值的类型是int还是short或者其他基础类型,亦或者是引用的地址?比如以int为例,4个字节只够存储int数据本身,并没有多余的空间存储数据的类型!**

想解答这个问题,需要从字节码入手,还需要我们了解一些Java虚拟机规范的知识, 来看一个简单的例子

public class Apple extends Fruit{
    private int color;
    private String name;
    private Apple brother;
    private long create_time;

    public void test() {
        int color = this.color;
        String name = this.name;
        Apple brother = this.brother;
        long create_time = this.create_time;
    }
}

很简单的一个Apple类,继承于Fruit,有一个test方法,将类成员变量赋值给方法本地变量,还是老套路,javac,javap 查看字节码

javac Fruit.java Apple.java
javap -verbose Apple.class

// 输出Apple字节码
public class com.company.alloc.Apple extends com.company.alloc.Fruit
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #9.#25         // com/company/alloc/Fruit."<init>":()V
   #2 = Fieldref           #8.#26         // com/company/alloc/Apple.color:I
   #3 = Fieldref           #8.#27         // com/company/alloc/Apple.name:Ljava/lang/String;
   #4 = Fieldref           #8.#28         // com/company/alloc/Apple.brother:Lcom/company/alloc/Apple;
   #5 = Fieldref           #8.#29         // com/company/alloc/Apple.create_time:J
   // 省略......
{
 // 省略......
  public void test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=6, args_size=1
         0: aload_0
         1: getfield      #2                  // Field color:I
         4: iconst_1
         5: iadd
         6: istore_1
         7: aload_0
         8: getfield      #3                  // Field name:Ljava/lang/String;
        11: astore_2
        12: aload_0
        13: getfield      #4                  // Field brother:Lcom/company/alloc/Apple;
        16: astore_3
        17: aload_0
        18: getfield      #5                  // Field create_time:J
        21: ldc2_w        #6                  // long 3l
        24: lsub
        25: lstore        4
        27: return
        // 省略......
}


我们重点看Apple类的test方法,我已经添加了注释

         // 加载Apple对象本身到栈
         0: aload_0
         // 获取字段,#2 对应常量池中的序列,
         // #2 = Fieldref           #8.#26         // com/company/alloc/Apple.color:I
         // 存储的类型是int类型
         1: getfield      #2                  // Field color:I
         // 加载1这个常量进栈
         4: iconst_1
         // 执行加法
         5: iadd
         // 将栈顶的值存到本地变量表1的位置
         6: istore_1
         // 加载Apple对象本身到栈
         7: aload_0
         // 获取字段,#3 对应常量池中的序列,
         8: getfield      #3                  // Field name:Ljava/lang/String;
         // 将栈顶的值存到本地变量表2的位置
        11: astore_2
         // .......

可以看到对于对象的成员变量,会存在一个常量池,保存该对象所属类的所有字段的索引表,根据这个常量池可以查询到变量的类型,而字节码指令对于操作各种类型都有专门的指令,比如存储int是istore,存储对象是astore,存储long是lstore,所以指令是编译期已经确定了,虚拟机只需要根据指令执行就行,根本不关心它操作的这个地址是什么类型的,所以也就不用额外的字段去存类型了,解答我们前面提的问题!

Java数据类型有哪些

在Java中数据类型分为二大类。

  • 基础数据类型(primitive type)
  • 引用类型 (reference type)

基础数据类型

Java中基础数据类型有8种,分别是byte(1), short(2), int(4), long(8), float(4), double(8), char(2), boolean(1), 括号里面是它们占用的字节数,所以对于基础数据类型,它们所占用的内存是很确定的,也就没什么好说的, 简单的记忆一下每种类型存储所需的字节数即可。

Java中基础数据类型是在栈上分配还是在堆上分配? 我们继续深究一下,基本数据类占用内存大小是固定的,那具体是在哪分配的呢,是在堆还是栈还是方法区?大家不妨想想看! 要解答这个问题,首先要看这个数据类型在哪里定义的,有以下三种情况。

  • 如果在方法体内定义的,这时候就是在栈上分配的
  • 如果是类的成员变量,这时候就是在堆上分配的
  • 如果是类的静态成员变量,在方法区上分配的

引用类型

引用类型跟基础数据类型不一样,除了对象本身之外,还存在一个指向它的引用(指针),指针占用的内存在64位虚拟机上8个字节,如果开启指针压缩是4个字节,默认是开启了的。 为了方便说明,还是以代码为例

class Kata {
  // str1和它指向的对象 都在堆上
  String str1 = new String();
  // str2和它指向的对象都在方法区上
  static String str2 = new String();

  public void methodTest() {
     // str3 在栈上,它指向的对象在堆上(也有可能在栈上,后面会说明)
     String str3 = new String();
  }
}

Java对象到底占多大内存?

指针的长度是固定的,不去说它了,重点看它所指向的对象在内存中占多少内存。 Java对象有三大类

  • 类对象
  • 数组对象
  • 接口对象

Java虚拟机规范定义了对象类型在内存中的存储规范,由于现在基本都是64位的虚拟机,所以后面的讨论都是基于64位虚拟机。 首先记住公式,对象由 对象头 + 实例数据 + padding填充字节组成,虚拟机规范要求对象所占内存必须是8的倍数,padding就是干这个的

对象头

而Java中对象头由 Markword + 类指针kclass(该指针指向该类型在方法区的元类型) 组成。

Markword

Hotspot虚拟机文档 “oops/oop.hp”有对Markword字段的定义

  64 bits:
  --------
  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
  size:64 ----------------------------------------------------->| (CMS free block)

这里简单解释下这几种object

  • normal object,初始new出来的对象都是这种状态
  • biased object,当某个对象被作为同步锁对象时,会有一个偏向锁,其实就是存储了持有该同步锁的线程id,关于偏向锁的知识这里就不再赘述了,大家可以自行查阅相关资料。
  • CMS promoted object 和 CMS free block 我也不清楚到底是啥,但是看名字似乎跟CMS 垃圾回收器有关,这里我们也可以暂时忽略它们

我们主要关注normal object, 这种类型的Object的 Markword 一共是8个字节(64位),其中25位暂时没有使用,31位存储对象的hash值(注意这里存储的hash值对根据对象地址算出来的hash值,不是重写hashcode方法里面的返回值),中间有1位没有使用,还有4位存储对象的age(分代回收中对象的年龄,超过15晋升入老年代),最后三位表示偏向锁标识和锁标识,主要就是用来区分对象的锁状态(未锁定,偏向锁,轻量级锁,重量级锁)

// 无其他线程竞争的情况下,由normal object变为biased object
synchronized(object)

biased object的对象头Markword前54位来存储持有该锁的线程id,这样就没有空间存储hashcode了,所以 对于没有重写hashcode的对象,如果hashcode被计算过并存储在对象头中,则该对象作为同步锁时,不会进入偏向锁状态,因为已经没地方存偏向thread id了,所以我们在选择同步锁对象时,最好重写该对象的hashcode方法,使偏向锁能够生效。

kclass

kclass存储的是该对象所属的类在方法区的地址,所以是一个指针,默认Jvm对指针进行了压缩,用4个字节存储,如果不压缩就是8个字节。 关于Compressed Oops的知识,大家可以自行查阅相关资料来加深理解。 Java虚拟机规范要求对象所占空间的大小必须是8字节的倍数,之所以有这个规定是为了提高分配内存的效率,我们通过实例来做说明

class Fruit extends Object {
     private int size;
}

Object object = new Object();
Fruit fruit = new Fruit();

有一个Fruit类继承了Object类,我们分别新建一个object和fruit,那他们分别占用多大的内存呢?

  • 先来看object对象,通过上面的知识,它的Markword是8个字节,kclass是4个字节, 加起来是12个字节,加上4个字节的对齐填充,所以它占用的空间是16个字节。
  • 再来看fruit对象,同样的,它的Markword是8个字节,kclass是4个字节,但是它还有个size成员变量,int类型占4个字节,加起来刚好是16个字节,所以不需要对齐填充。

那该如何验证我们的结论呢?毕竟我们还是相信眼见为实!很幸运Jdk提供了一个工具jol-core可以让我们来分析对象头占用内存信息。 jol的使用也很简单

// 打印对象头信息代码
System.out.println(ClassLayout.parseClass(Object.class).toPrintable());
System.out.println(ClassLayout.parseClass(Fruit.class).toPrintable());

// 输出结果
java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0    12        (object header)                           N/A
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

com.aliosuwang.jol.Fruit object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0    12        (object header)                           N/A
     12     4    int Fruit.size                                N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

可以看到输出结果都是16 bytes,跟我们前面的分析结果一致。 除了类类型和接口类型的对象,Java中还有数组类型的对象,数组类型的对象除了上面表述的字段外,还有4个字节存储数组的长度(所以数组的最大长度是Integer.MAX)。所以一个数组对象占用的内存是 8 + 4 + 4 = 16个字节,当然这里不包括数组内成员的内存。 我们也运行验证一下。

String[] strArray = new String[0];
System.out.println(ClassLayout.parseClass(strArray.getClass()).toPrintable());

// 输出结果
[Ljava.lang.String; object internals:
 OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
      0    16                    (object header)                           N/A
     16     0   java.lang.String String;.<elements>                        N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

输出结果object header的长度也是16,跟我们分析的一致。到这里对象头部分的内存分配我们就了解的差不多了,接下来看对象的实例数据部分。

对象的实例数据(成员变量)的分配规则

为了方便说明,我们新建一个Apple类继承上面的Fruit类

public class Apple extends Fruit{
    private int size;
    private String name;
    private Apple brother;
    private long create_time;
}

// 打印Apple的对象分布信息
System.out.println(ClassLayout.parseClass(Apple.class).toPrintable());

// 输出结果
com.aliosuwang.jol.Apple object internals:
 OFFSET  SIZE                       TYPE DESCRIPTION                               VALUE
      0    12                           (object header)                           N/A
     12     4                       int Fruit.size                                N/A
     16     8                      long Apple.create_time                         N/A
     24     4                       int Apple.size                                N/A
     28     4          java.lang.String Apple.name                                N/A
     32     4   com.company.alloc.Apple Apple.brother                             N/A
     36     4                            (loss due to the next object alignment)
Instance size: 40 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

可以看到Apple的对象头12个字节,然后分别是从Fruit类继承来的size属性(虽然Fruit的size是private的,还是会被继承,与Apple自身的size共存),还有自己定义的4个属性,基础数据类型直接分配,对象类型都是存的指针占4个字节(默认都是开启了指针压缩),最终是40个字节,所以我们new一个Apple对象,直接就会占用堆栈中40个字节的内存,清楚对象的内存分配,让我们在写代码时心中有数,应当时刻有内存优化的意识! 这里又引出了一个小知识点,上面其实已经标注出来了。

父类的私有成员变量是否会被子类继承?

答案当然是肯定的,我们上面分析的Apple类,父类Fruit有一个private类型的size成员变量,Apple自身也有一个size成员变量,它们能够共存。注意划重点了,类的成员变量的私有访问控制符private,只是编译器层面的限制,在实际内存中不论是私有的,还是公开的,都按规则存放在一起,对虚拟机来说并没有什么分别!

方法内部new的对象是在堆上还是栈上?

我们常规的认识是对象的分配是在堆上,栈上会有个引用指向该对象(即存储它的地址),到底是不是呢,我们来做个试验! 我们在循环内创建一亿个Apple对象,并记录循环的执行时间,前面已经算过1个Apple对象占用40个字节,总共需要4GB的空间。

public static void main(String[] args) {
     long startTime = System.currentTimeMillis();
     for (int i = 0; i < 100000000; i++) {
         newApple();
     }
     System.out.println("take time:" + (System.currentTimeMillis() - startTime) + "ms");
}

public static void newApple() {
     new Apple();
}

我们给JVM添加上-XX:+PrintGC运行配置,让编译器执行过程中输出GC的log日志

// 运行结果,没有输出任何gc的日志
take time:6ms

1亿个对象,6ms就分配完成,而且没有任何GC,显然如果对象在堆上分配的话是不可能的,其实上面的实例代码,Apple对象全部都是在栈上分配的,这里要提出一个概念指针逃逸,newApple方法中新建的对象Apple并没有在外部被使用,所以它被优化为在栈上分配,我们知道方法执行完成后该栈帧就会被清空,所以也就不会有GC。 我们可以设置虚拟机的运行参数来测试一下。

// 虚拟机关闭指针逃逸分析
-XX:-DoEscapeAnalysis
// 虚拟机关闭标量替换
-XX:-EliminateAllocations

在VM options里面添加上面二个参数,再运行一次

[GC (Allocation Failure)  236984K->440K(459776K), 0.0003751 secs]
[GC (Allocation Failure)  284600K->440K(516608K), 0.0004272 secs]
[GC (Allocation Failure)  341432K->440K(585216K), 0.0004835 secs]
[GC (Allocation Failure)  410040K->440K(667136K), 0.0004655 secs]
[GC (Allocation Failure)  491960K->440K(645632K), 0.0003837 secs]
[GC (Allocation Failure)  470456K->440K(625152K), 0.0003598 secs]
take time:5347ms
复制代码

可以看到有很多GC的日志,而且运行的时间也比之前长了很多,因为这时候Apple对象的分配在堆上,而堆是所有线程共享的,所以分配的时候肯定有同步机制,而且触发了大量的gc,所以效率低很多。 总结一下: 虚拟机指针逃逸分析是默认开启的,对象不会逃逸的时候优先在栈上分配,否则在堆上分配。 到这里,关于“一个对象占多少内存?”这个问题,已经能回答的相当全面了。但是毕竟我们分析的只是Hotspot虚拟机,我们不妨延伸一下,看在Android ART虚拟机上面的分配情况

获取Android ART虚拟机上面的对象头大小

我们前面使用了jol工具来输出对象头的信息,但是这个jol工具只能用在hotspot虚拟机上,那我们如何在Android上面获取对象头大小呢?

方法的灵感来源

办法肯定是有的,我这里介绍的办法,灵感的主角就是AtomicInteger,我是受到它的启发,这个类我们知道是线程安全的int的包装类。它的实现原理是利用了Unsafe包提供的CAS能力,不妨看下它的源码实现

    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
    private static final long VALUE;

    static {
        try {
            VALUE = U.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (ReflectiveOperationException e) {
            throw new Error(e);
        }
    }

    private volatile int value;

    /**
     * Atomically increments by one the current value.
     *
     * @return the previous value
     */
    public final int getAndIncrement() {
        return U.getAndAddInt(this, VALUE, 1);
    }

我们知道普通int对象的++操作不是原子性的,AtomicInteger提供了getAndIncrement()它却能保证原子性,这一部分知识不是我们这篇要讲的知识点,就不去说它们了。 getAndIncrement()方法内部调用了Unsafe对象的getAndAddInt()方法,第二个参数是VALUE,这个VALUE大有玄机,它表示成员变量在对象内存中的偏移地址,根据前面的知识,普通对象的结构 就是 对象头+实例数据+对齐字节,那如果我们能获取到第一个实例数据的偏移地址,其实就是获得了对象头的字节大小。

如何拿到并使用Unsafe

因为Unsafe是不可见的类,而且它在初始化的时候有检查当前类的加载器,如果不是系统加载器会报错。但是好消息是,AtomicInteger中定义了一个Unsafe对象,而且是静态的,我们可以直接通过反射来得到。

    public static Object getUnsafeObject() {
        Class clazz = AtomicInteger.class;
        try {
            Field uFiled = clazz.getDeclaredField("U");
            uFiled.setAccessible(true);
            return uFiled.get(null);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

拿到了Unsafe,我们就可以通过调用它的objectFieldOffset静态方法来获取成员变量的内存偏移地址。

    public static long getVariableOffset(Object target, String variableName) {
        Object unsafeObject = getUnsafeObject();
        if (unsafeObject != null) {
            try {
                Method method = unsafeObject.getClass().getDeclaredMethod("objectFieldOffset", Field.class);
                method.setAccessible(true);
                Field targetFiled = target.getClass().getDeclaredField(variableName);
                return (long) method.invoke(unsafeObject, targetFiled);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
        return -1;
    }

    public static void printObjectOffsets(Object target) {
        Class targetClass = target.getClass();
        Field[] fields = targetClass.getDeclaredFields();
        for (Field field : fields) {
            String name = field.getName();
            Log.d("offset", name + " offset: " + getVariableOffset(target, name));
        }
    }

我们来使用上面的工具测试打印之前的Fruit和Apple,

        Log.d("offset", "------start print fruit offset!------");
        Utils.printObjectOffsets(new Fruit());

        Log.d("offset", "------start print apple offset!------");
        Utils.printObjectOffsets(new Apple());

        // 输出结果 (Android 8.0模拟器)
        offset: ------start print fruit offset!------
        offset: size offset: 8
        offset: ------start print apple offset!------
        offset: brother offset: 12
        offset: create_time offset: 24
        offset: id offset: 20
        offset: name offset: 16

通过输出结果,看出在 Android8.0 ART 虚拟机上,对象头的大小是8个字节,这跟hotspot虚拟机不同(hotspot是12个字节默认开启指针压缩),根据输出的结果目前只发现这一点差别,各种数据类型占用的字节数都是一样的,比如int占4个字节,指针4个字节,long8个字节等,都一样。

总结

全文我们总结了以下几个知识点

  • Java虚拟机通过字节码指令来操作内存,所以可以说它并不关心数据类型,它只是按指令行事,不同类型的数据有不同的字节码指令。
  • Java中基本数据类型和引用类型的内存分配知识,重点分析了引用类型的对象头,并介绍了JOL工具的使用
  • 延伸到Android平台,介绍了一种获取Android中对象的对象头信息的方法,并对比了ART和Hotspot虚拟机对象头长度的差别。
如何查看Java对象的内存占用大小 本文介绍了两种方法来查看Java对象的内存占用大小,分别使用了Instrumentation类和Java提供的工具类。接着,我们通过计算对象所占用的内存前后的堆内存使用量之差,即可得到对象的内存占用大小。需要注意的是,由于Java的垃圾回收机制的存在,对象的内存占用大小可能会受到垃圾回收的影响。然后,在您的代码中调用ObjectSizeFetcher.getObjectSize方法,传入要检测内存大小的对象,即可获取其内存占用大小。本文将介绍几种方法,可用于查看Java对象的内存占用大小。 阅读详情

相关推荐

机载电脑与飞控串口通信(实测读取飞控IMU数据)《一、香橙派5max启动串口UART通信与飞控板通信,一次必通!》《二、allspark1与PIX6C通信踩坑及出坑》《三、orinnx载板与飞控通信》

机载电脑与飞控串口通信(实测读取飞控IMU数据)《一、香橙派5max启动串口UART通信与雷迅v5nano飞控板通信,一次必通!》《二、阿木机载电脑allspark1与PIX6C通信踩坑及出坑》,还有如何打开飞控串口以及如何提高飞控IMU频率。

2402_82745259的博客 3471

一个Java对象占用多大内存

我们主要关注 normal object, 这种类型的 Object 的 Markword 一共是 8 个字节(64位),其中 25 位暂时没有使用,31 位存储对象的 hash 值(注意这里存储的 hash 值对根据对象地址算出来的 hash 值,不是重写 hashcode 方法里面的返回值),中间有 1 位没有使用,还有 4 位存储对象的 age(分代回收中对象的年龄,超过 15 晋升入老年代),最后三位表示偏向锁标识和锁标识,主要就是用来区分对象的锁状态(未锁定,偏向锁,轻量级锁,重量级锁)

meser88的博客 1752

从零搭建高通8255车载开发环境:QNX SDP、SDK配置与镜像编译全流程

本文详细介绍了如何从零搭建高通SA8255P车载开发环境,涵盖QNX SDP部署、SDK工具链配置到多系统镜像编译的全流程。特别针对SAIL安全岛镜像构建、QNX系统优化及Android系统资源分配等关键技术点提供实战指导,帮助开发团队高效完成车载系统开发与调试。

weixin_33582311的博客 368

一个空的Java object 对象占多大内存?

对象头:  1.MakeOop :存储hashcode 垃圾回收时候的分代年龄 synchronized锁升级过程中的锁标记 (无锁、偏向锁、轻量级锁、重量级锁) 32位操作系统占4个字节 64位操作系统占8个字节。在开启了压缩指针的情况下,Object默认会占用12个字节,但是为了避免伪共享问题,JVM会按照8个字节的倍数进行填充,所以会填充4个字节变成16个字节长度。在关闭压缩指针的情况下,Object默认会占用16个字节,16个字节正好是8的整数倍,因此不需要填充。

mischen520的博客 3263

TypeScript的安装与使用

TypeScript的安装与使用

qq_51589308的博客 600

永磁同步电机无传感器控制:HFI与ESMO技术详解

高频注入(HFI)和增强型滑模观测器(ESMO)是现代永磁同步电机(PMSM)无传感器控制的核心技术。HFI通过注入高频信号利用电机凸极效应获取转子位置,而ESMO则通过改进传统滑模观测器,有效抑制抖振并提升动态响应。这两种技术的结合特别适用于零低速区域的位置估计,在工业伺服、电动汽车等领域有广泛应用。方波高频注入作为实现方案之一,具有计算量小、实现简单的特点,配合自适应滤波等信号处理技术,可以在保证精度的同时降低系统成本。

weixin_29183637的博客 357

4种方法教你如何查看java对象所占内存大小

如果需要查看某个对象的详细内存分布,可以借助jol工具类,不过这种当对象中内嵌其他对象时,只能计算ClassLayout方法中这个object对象所占内存的大小。当一个对象有多个属性,需要计算整个对象的大小时,可以借助org.apache.lucene工具类。使用这种jdk8方式时,Open JDK 不是天然支持的,需要set一下环境变量。最后,计算一个对象占用多大内存,需要提前了解java对象的布局,可以参考这篇。先引入maven坐标。先导入maven坐标。

moonNife的专栏 9691

别再傻傻分不清了!用Design Compiler和PrimeTime实操对比PBA与GBA模式

本文深度解析静态时序分析(STA)中Design Compiler与PrimeTime工具的PBA与GBA模式差异,通过实际案例演示两种模式在转换时间计算、时钟路径分析等方面的对比,并提供工程实践中模式选择的策略与调试技巧,帮助工程师在芯片设计流程中平衡精度与效率。

weixin_42552315的博客 415

一个Java对象到底占多少内存你竟然还不知道?

内存是程序员逃不开的话题,当然Java因为有GC使得我们不用手动申请和释放内存,但是了解Java内存分配是做内存优化的基础,如果不了解Java内存分配的知识,可能会带偏我们内存优化的方向。所以这篇文章我们以“一个对象占多少内存”为引子来谈谈Java内存分配。 文章标题提出的问题是”一个对象到底占多少内存“,看似很简单,但想说清楚并不容易,希望本文的探讨能让你有收获。 在开始之前我还是决定先提一个曾经阴魂不散,困扰我很久的问题,了解这个问题的答案有助于我们理解接下来的内容。 Java虚拟机如何在运行.

yuandengta的博客 633

图像调整亮度饱和度 c语言,【C#/WPF】调节图像的HSL(色相、饱和度、明亮度)...

先说概念:HSL是一种描述颜色的方式(其他颜色描述方式还有大家熟悉的RGB值)。HSL三个字母分别表示图像的Hue色相、Saturation饱和度、Lightness明亮度。需求:制作一个面板,包含三个滑动条,拖动滑动条可以修改目标图片的HSL值。即模仿PS中类似的功能,如下图:方案一:遍历所有像素点,修改每个点的HSL值。前台界面:一个Image控件显示目标图片,一个Button按钮点击一下降低...

weixin_39935777的博客 1157

『言善信』Fiddler工具 — 1、Fiddler介绍与安装

文章目录1、Fiddler简介2、Fiddler功能3、Fiddler工作原理4、Fiddler安装 1、Fiddler简介 Fiddler是强大的抓包工具之一,它能记录所有客户端和服务器之间的HTTP和HTTPS请求,是web调试的利器。 Fiddler是位于客户端和服务端之间的HTTP代理,它的原理是以web代理服务器的形式进行工作的,使用的代理地址是:127.0.0.1,端口默认为8888,我们也可以通过设置进行修改。 Fiddler可以抓取支持HTTP代理的任意程序的数据包,如果要抓取https会

繁华似锦Fighting 1473

【JVM】一个Java对象到底占多少个字节?

文章目录一、JAVA对象模型1.1 对象头(Header)1.2 内存对齐二、非空对象占用内存计算三、总结 问题 一个Java对象到底占多少个字节?了解这个之前我们先来了解一下Java对象模型,这将对我们理解具有帮助。 一、JAVA对象模型   我们先了解一下,一个JAVA对象的存储结构。在Hotspot虚拟机中,对象在内存中的存储布局分为 3 块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。 1.1 对象头(Header)   对象头,又包括三部分:M

时光、疏离了记忆づ童话的博客 6874

H3C BGP联盟实验

bgp,bgp联盟,bgp公认团体属性,

一只懒羊羊 971

重学Java-一个Java对象到底占多少内存

内存是程序员逃不开的话题,当然Java因为有GC使得我们不用手动申请和释放内存,但是了解Java内存分配是做内存优化的基础,如果不了解Java内存分配的知识,可能会带偏我们内存优化的方向。所以这篇文章我们以“一个对象占多少内存”为引子来谈谈Java内存分配。 文章基于JDK版本:1.8.0_191 文章标题提出的问题是”一个对象到底占多少内存“,看似很简单,但想说清楚并不容易,希望本文的探讨能...

weixin_30394333的博客 277

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

一个对象到底占多少内存?

内存是程序员逃不开的话题,当然Java因为有GC使得我们不用手动申请和释放内存,但是了解Java内存分配是做内存优化的基础,如果不了解Java内存分配的知识,可能会带偏我们内存优化的方向。所以这篇文章我们以“一个对象占多少内存”为引子来谈谈Java内存分配。 文章基于JDK版本:1.8.0_191 文章标题提出的问题是”一个对象到底占多少内存“,看似很简单,但想说清楚并不容易,希望本文的探讨能让你有收获。 在开始之前我还是决定先提一个曾经阴魂不散,困扰我很久的问题,了解这个问题的答案有助于我们理解接.

n_fly的博客 1205

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

解析一个Java对象占用多少内存空间

说明: alignment, 对齐, 比如8字节的数据类型long, 在内存中的起始地址必须是8的整数倍。 padding, 补齐; 在对象所占据空间的末尾,如果有空白, 需要使用padding来补齐, 因为下一个对象的起始位置必须是4/8字节(32bit/64bit)的整数倍(这又是一种对齐)。 问题描述 一个对象具有100个属性, 与100个对象每个具有1个属性, 哪个占用的内存空间更大...

铁锚的优快云博客 1万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

new一个对象到底占了多少内存

一.对象的创建 当Java虚拟机遇到一条字节码new指令时,首先将去检查这个指令的参数是否能在常量池中定位到 一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。 1.空间分配 指针碰撞 假设Java堆中内存是绝对规整的,所有被使用过的内存都被放在一 边,空闲的内存被放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那 个指针向空闲空间方向挪动一段与对象大小相等的距离(Serial、ParNew使用) 空间列表 但如果Jav

程序员麦冬的博客(公众号同名) 2238

Java-一个对象到底占多少内存?

内存是程序员逃不开的话题,当然Java因为有GC使得我们不用手动申请和释放内存,但是了解Java内存分配是做内存优化的基础,如果不了解Java内存分配的知识,可能会带偏我们内存优化的方向。所以这篇文章我们以“一个对象占多少内存”为引子来谈谈Java内存分配。 文章基于JDK版本:1.8.0_191 文章标题提出的问题是”一个对象到底占多少内存“,看似很简单,但想说清楚并不容易,希望本文的探...

WYwysun的博客 540

你写的Java对象究竟占多少内存?

Java 作为一个面向对象语言,给我们带来了多态,继承,封装等特性,使得我们可以利用这些特性很轻松的就能构建出易于扩展,易于维护的代码。 作为一个Javaer,天天搞“对象”,那你写的对象究竟占用了多少内存呢? 我们来看看你的“对象”是如何“败家”的。 本文环境:jdk1.8_64 Java 对象头内存模型 我们先来看看,一个Java 对象的内存模型是怎么样的? 由于我们的虚拟机是分为32位和...

qianlia的博客 924

Java-对象到底占多少个字节?计算规则是什么?

学会计算java的内存会极大地降低内存溢出的风险,以及最大化利用内存来达到最好的效率,建议学一下Java-垃圾收回机制,因为只会计算对象大小也不行的,还需要结合JVM虚拟机的GC机制和实际需求进行计算,假设你堆大小2G你在某一时间创建了2G的对象,那么会溢出吗?可能会,也可能不会,主要看这些对象在gc的时候能否被收回,那么如何知道这些对象满足了收回的条件,就要研究GC机制了…书山有路勤为径,学海无涯苦作舟有其他问题在评论区讨论-或者私信我-收到会在第一时间回复httpshttpshttps。........

weixin_45203607的博客 3779

你写的Java对象究竟占多少内存?

个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈 概述 Java 作为一个面向对象语言,给我们带来了多态,继承,封装等特性,使得我们可以利用这些特性很轻松的就能构建出易于扩展,易于维护的代码。作为一个Javaer,天天搞“对象”,那你写的对象究竟占用了多少内存呢?我们来看看你的“对象”是如何“败家”的。 本文环境:jdk1.8_64 Java 对象头内存模型 ...

JKX_geek的博客 367
上一篇: Java 的业务逻辑验证框架指的是?
下一篇: 怎样解析java中的封装
Java_ttcd
博客等级 码龄4年 198粉丝 190原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值