精华内容
下载资源
问答
  • 2021-03-07 15:07:35

    ai里面改变对象大小的快捷键是什么

    AI是直接放大缩小的,不用快捷键,有固定尺寸的话输入数字即可。 快捷键,又叫快速键或热键,指通过某些特定的按键、按键顺序或按键组合来完成一个操作,很多快捷键往往与如 Ctrl 键、Shift 键、Alt 键、Fn 键以及 Windows 平台下的 Windows 键和

    AI中怎么把图像等比例扩大或缩小尺寸

    a3ecd2d6dc2d492c7cbb9ce3b0ef52d4.png

    就像在PS中图像大小和画布大小

    一:按照固定尺寸等比缩放:选中对象,Shift+F8打开变换面板,面板右边有一个类似锁链的按钮可以锁定对象的高宽比例,锁定后在输入你要的高或者宽的长度,另一边会自动按照比例改变。 二:无固定尺寸的等比缩放:选中对象,按住Shift不放。

    AI中怎样设置对象全部间距一样

    在AI中找到需要编辑的文件,可以看出上下间距不同,需要调整;

    使用黑色箭头将文件中的内容全部选中;

    然后打开窗口栏下的对齐命令;

    在对其面板下方的分布对象一栏中,选择第二个选项:垂直居中分布;

    ai矢量图形如何组合调整大小Ctrl+A(全选),Ctrl+G(群组),V选择工具缩放(调整大小)。

    AI软件,如何调整图片尺寸?

    我没用过AI软件,别人给我的图,是60*2的,但需要做成40*2的, 这是一个门头首先打开电脑桌面上ai的软件,点击执行菜单栏中的文件—新建,或者直接按快捷键Ctrl+N新建一个画板。

    然后在执行菜单栏中的窗口中下拉找到并且选择画板这个选项。

    点击画板后,出现画板面板,在画板面板中的右边,单击一下。

    我只是想提示下那些分不清画板和画布的人。

    AI里面怎么改变文件的尺寸?

    以下图中AI文档为例演示查看方法。

    鼠标移到菜单栏的点击“窗口”菜单。弹出下拉菜单,再点:文档信息

    弹出文档信息面板,在此面板中,我们就看到了页面大小啦。

    转到编辑画板界面,如图所示,点击画板选项按钮。

    如何像CORELDRAW那样,可以输入数据改变图形的大小,比如一个黄色的矩形准备材料:电脑、AI

    打开AI之后在AI的工具箱内找到矩形工具,

    选择矩形工具我们在绘图区里绘制一个矩形

    选择矩形在上面的填充里找到需要的填充图案

    点击选择的填充图案之后,可以看到填充后的效果

    在工具箱内后找道比例缩放工具

    AI里如何更改版面大小我用的AI4,请问如何更改他的版面大小????还有就是如何绘制一个与版面一AI只能在建立新文档的时候设置版面大小,设置好大小之后就不能再进行调整的了。 绘制一个与版面一样的距形你必须要在知道版面的尺寸,然后选择矩形工具,在版面空白处点击一下鼠标左键,在弹出框里输入长宽的数值,点确定即可。

    AI怎样同时等比缩放多个对象但位置不动,比如A,B,C如题

    先用选择工具全选所有对象,

    然后快捷键CTRL+SHIFT+ALT+D,分别变换,在菜单栏“对象-变换-分别变换”这样操作是一样的,

    然后设置水平垂直方向的缩放,注意下面选项选变换对象打勾,最后确定就可以了。

    更多相关内容
  • JVM之内存布局与对象大小

    千次阅读 2020-07-15 06:39:27
    在Java中基本数据类型的大小, 例如int类型占4个字节、long类型占8个字节,那么Integer对象和Long对象会占用多少内存呢? 本文结合JVM相关的书籍以及网上的大神, 从基本数据类型到对应的包装类型、再到引用类型,也...

    本文章来源于:https://github.com/Zeb-D/my-review ,请star 强力支持,你的支持,就是我的动力。

    Java对象内存布局

    [TOC]


    在Java中基本数据类型的大小,

    例如int类型占4个字节、long类型占8个字节,那么Integer对象和Long对象会占用多少内存呢?

    本文结合JVM相关的书籍以及网上的大神,

    从基本数据类型到对应的包装类型、再到引用类型,也会从指针压缩(64位机器)来分别探讨对象的内存结构以及对象大小

    对象的内存布局

    一个Java对象在内存中包括对象头、实例数据和补齐填充3个部分:

    img

    对象头

    • Mark Word:包含一系列的标记位,比如轻量级锁的标记位,偏向锁标记位等等。在32位系统占4字节,在64位系统中占8字节;
    • Class Pointer:用来指向对象对应的Class对象(其对应的元数据对象)的内存地址。在32位系统占4字节,在64位系统中占8字节;
    • Length:如果是数组对象,还有一个保存数组长度的空间,占4个字节;

    对象实际数据

    对象实际数据包括了对象的所有成员变量,其大小由各个成员变量的大小决定,比如:byte和boolean是1个字节,short和char是2个字节,int和float是4个字节,long和double是8个字节,reference是4个字节(64位系统中是8个字节)。

    Primitive TypeMemory Required(bytes)
    boolean1
    byte1
    short2
    char2
    int4
    float4
    long8
    double8

    对于reference类型来说,在32位系统上占用4bytes, 在64位系统上占用8bytes。

    对齐填充

    Java对象占用空间是8字节对齐的,即所有Java对象占用bytes数必须是8的倍数。例如,一个包含两个属性的对象:int和byte,这个对象需要占用8+4+1=13个字节,这时就需要加上大小为3字节的padding进行8字节对齐,最终占用大小为16个字节。

    注意:以上对64位操作系统的描述是未开启指针压缩的情况,关于指针压缩会在下文中介绍。

    对象头占用空间大小

    这里说明一下32位系统和64位系统中对象所占用内存空间的大小:

    • 在32位系统下,存放Class Pointer的空间大小是4字节,MarkWord是4字节,对象头为8字节;
    • 在64位系统下,存放Class Pointer的空间大小是8字节,MarkWord是8字节,对象头为16字节;
    • 64位开启指针压缩的情况下,存放Class Pointer的空间大小是4字节,MarkWord是8字节,对象头为12字节;
    • 如果是数组对象,对象头的大小为:数组对象头8字节+数组长度4字节+对齐4字节=16字节。其中对象引用占4字节(未开启指针压缩的64位为8字节),数组MarkWord为4字节(64位未开启指针压缩的为8字节);
    • 静态属性不算在对象大小内。

    指针压缩

    从上文的分析中可以看到,64位JVM消耗的内存会比32位的要多大约1.5倍,这是因为对象指针在64位JVM下有更宽的寻址。对于那些将要从32位平台移植到64位的应用来说,平白无辜多了1/2的内存占用,这是开发者不愿意看到的。

    从JDK 1.6 update14开始,64位的JVM正式支持了 -XX:+UseCompressedOops 这个可以压缩指针,起到节约内存占用的新参数。

    什么是OOP?

    OOP的全称为:Ordinary Object Pointer,就是普通对象指针。启用CompressOops后,会压缩的对象:

    • 每个Class的属性指针(静态成员变量);
    • 每个对象的属性指针;
    • 普通对象数组的每个元素指针。

    当然,压缩也不是所有的指针都会压缩,对一些特殊类型的指针,JVM是不会优化的,例如指向PermGen的Class对象指针、本地变量、堆栈元素、入参、返回值和NULL指针不会被压缩。

    启用指针压缩

    在Java程序启动时增加JVM参数:-XX:+UseCompressedOops来启用。

    注意:32位HotSpot VM是不支持UseCompressedOops参数的,只有64位HotSpot VM才支持。

    本文中使用的是JDK 1.8,默认该参数就是开启的。

    查看对象的大小

    接下来我们使用http://www.javamex.com/中提供的classmexer.jar来计算对象的大小。

    运行环境:JDK 1.8,Java HotSpot(TM) 64-Bit Server VM


    Shallow Size Retained Size

    普及下 计算对象属性及引用导致大小的相关概念

    Shallow Size 对象自身占用的内存大小,不包括它引用的对象。 针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。当然这里面还会包括一些java语言特性的数据存储单元。 针对数组类型的对象,它的大小是数组元素对象的大小总和。

    Retained Size Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C, C就是间接引用) 换句话说,Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存。 不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。

    有关Shallow Size和Retained Size 详细请参考http://blog.csdn.net/e5945/article/details/7708253

    基本数据类型

    对于基本数据类型来说,是比较简单的,因为我们已经知道每个基本数据类型的大小。代码如下:

    /**
     * VM options:
     * -javaagent:/Users/sangjian/dev/source-files/classmexer-0_03/classmexer.jar
     * -XX:+UseCompressedOops
     */
    public class TestObjectSize {
    
    
        int a;
        long b;
        static int c;
    
        public static void main(String[] args) throws IOException {
            TestObjectSize testObjectSize = new TestObjectSize();
            // 打印对象的shallow size
            System.out.println("Shallow Size: " + MemoryUtil.memoryUsageOf(testObjectSize) + " bytes");
            // 打印对象的 retained size
            System.out.println("Retained Size: " + MemoryUtil.deepMemoryUsageOf(testObjectSize) + " bytes");
            System.in.read();
        }
    }

    注意:在运行前需要设置javaagent参数,在JVM启动参数中添加-javaagent:/path_to_agent/classmexer.jar来运行。


    开启指针压缩的情况

    运行查看结果:

    Shallow Size: 24 bytes
    Retained Size: 24 bytes
    
    

    根据上文的分析可以知道,64位开启指针压缩的情况下:

    • 对象头大小=Class Pointer的空间大小为4字节+MarkWord为8字节=12字节;
    • 实际数据大小=int类型4字节+long类型8字节=12字节(静态变量不在计算范围之内)

    在MAT中分析的结果如下:

    img

    所以大小是24字节。其实这里并没有padding,因为正好是24字节。如果我们把long b;换成int b;之后,再来看一下结果:

    Shallow Size: 24 bytes
    Retained Size: 24 bytes
    
    

    大小并没有变化,说明这里做了padding,并且padding的大小是4字节。

    这里的Shallow Size和Retained Size是一样的,因为都是基本数据类型。

    关闭指针压缩的情况

    如果要关闭指针压缩,在JVM参数中添加-XX:-UseCompressedOops来关闭,再运行上述代码查看结果:

    Shallow Size: 24 bytes
    Retained Size: 24 bytes
    
    

    分析一下在64位未开启指针压缩的情况下:

    • 对象头大小=Class Pointer的空间大小为8字节+MarkWord为8字节=16字节;
    • 实际数据大小=int类型4字节+long类型8字节=12字节(静态变量不在计算范围之内);

    这里计算后大小为16+12=28字节,这时候就需要padding来补齐了,所以padding为4字节,最后的大小就是32字节。

    我们再把long b;换成int b;之后呢?通过上面的计算结果可以知道,实际数据大小就应该是int类型4字节+int类型4字节=8字节,对象头大小为16字节,那么不需要做padding,对象的大小为24字节:

    Shallow Size: 24 bytes
    Retained Size: 24 bytes
    
    

    数组类型

    64位系统中,数组对象的对象头占用24 bytes,启用压缩后占用16字节。比普通对象占用内存多是因为需要额外的空间存储数组的长度。基础数据类型数组占用的空间包括数组对象头以及基础数据类型数据占用的内存空间。由于对象数组中存放的是对象的引用,所以数组对象的Shallow Size=数组对象头+length * 引用指针大小,Retained Size=Shallow Size+length*每个元素的Retained Size。

    代码如下:

    /**
     * VM options:
     * -javaagent:/Users/sangjian/dev/source-files/classmexer-0_03/classmexer.jar
     * -XX:+UseCompressedOops
     */
    public class TestObjectSize {
    
    
        long[] arr = new long[6];
    
        public static void main(String[] args) throws IOException {
            TestObjectSize testObjectSize = new TestObjectSize();
            // 打印对象的shallow size
            System.out.println("Shallow Size: " + MemoryUtil.memoryUsageOf(testObjectSize) + " bytes");
            // 打印对象的 retained size
            System.out.println("Retained Size: " + MemoryUtil.deepMemoryUsageOf(testObjectSize) + " bytes");
            System.in.read();
        }
    }

    开启指针压缩的情况

    结果如下:

    Shallow Size: 16 bytes
    Retained Size: 80 bytes
    
    

    Shallow Size比较简单,这里对象头大小为12字节, 实际数据大小为4字节,所以Shallow Size为16。

    对于Retained Size来说,要计算数组占用的大小,对于数组来说,它的对象头部多了一个用来存储数组长度的空间,该空间大小为4字节,所以*数组对象的大小=引用对象头大小12字节+存储数组长度的空间大小4字节+数组的长度数组中对象的Retained Size+padding大小**

    下面分析一下上述代码中的long[] arr = new long[6];,它是一个长度为6的long类型的数组,由于long类型的大小为8字节,所以数组中的实际数据是68=48字节,那么数组对象的大小=12+4+68+0=64,最终的Retained Size=Shallow Size + 数组对象大小=16+64=80。

    通过MAT查看如下:

    img

    关闭指针压缩的情况

    结果如下:

    Shallow Size: 24 bytes
    Retained Size: 96 bytes
    
    

    这个结果大家应该能自己分析出来了,因为这时引用对象头为16字节,那么数组的大小=16+4+6*8+4=72,(这里最后一个4是padding),所以Retained Size=Shallow Size + 数组对象大小=24+72=96。

    通过MAT查看如下:

    img

    包装类型

    包装类(Boolean/Byte/Short/Character/Integer/Long/Double/Float)占用内存的大小等于对象头大小加上底层基础数据类型的大小。

    包装类型的Retained Size占用情况如下:

    Numberic Wrappers+useCompressedOops-useCompressedOops
    Byte, Boolean16 bytes24 bytes
    Short, Character16 bytes24 bytes
    Integer, Float16 bytes24 bytes
    Long, Double24 bytes24 bytes

    代码如下:

    /**
     * VM options:
     * -javaagent:/Users/sangjian/dev/source-files/classmexer-0_03/classmexer.jar
     * -XX:+UseCompressedOops
     */
    public class TestObjectSize {
    
    
        Boolean a = new Boolean(false);
        Byte b = new Byte("1");
        Short c = new Short("1");
        Character d = new Character('a');
        Integer e = new Integer(1);
        Float f = new Float(2.5);
        Long g = new Long(123L);
        Double h = new Double(2.5D);
    
        public static void main(String[] args) throws IOException {
            TestObjectSize testObjectSize = new TestObjectSize();
            // 打印对象的shallow size
            System.out.println("Shallow Size: " + MemoryUtil.memoryUsageOf(testObjectSize) + " bytes");
            // 打印对象的 retained size
            System.out.println("Retained Size: " + MemoryUtil.deepMemoryUsageOf(testObjectSize) + " bytes");
            System.in.read();
        }
    }
    
    
    

    开启指针压缩的情况

    结果如下:

    Shallow Size: 48 bytes
    Retained Size: 192 bytes
    
    

    MAT中的结果如下:

    img

    关闭指针压缩的情况

    结果如下:

    Shallow Size: 80 bytes
    Retained Size: 272 bytes
    
    

    MAT中的结果如下:

    img

    String类型

    在JDK1.7及以上版本中,java.lang.String中包含2个属性,一个用于存放字符串数据的char[], 一个int类型的hashcode, 部分源代码如下:

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
        private final char value[];
    
        /** Cache the hash code for the string */
        private int hash; // Default to 0
        ...
    }
    
    

    因此,在关闭指针压缩时,一个String对象的大小为:

    • Shallow Size=对象头大小16字节+int类型大小4字节+数组引用大小8字节+padding4字节=32字节
    • Retained Size=Shallow Size+char数组的Retained Size

    在开启指针压缩时,一个String对象的大小为:

    • Shallow Size=对象头大小12字节+int类型大小4字节+数组引用大小4字节+padding4字节=24字节
    • Retained Size=Shallow Size+char数组的Retained Size

    代码如下:

    /**
     * VM options:
     * -javaagent:/Users/sangjian/dev/source-files/classmexer-0_03/classmexer.jar
     * -XX:+UseCompressedOops
     */
    public class TestObjectSize {
    
    
        String s = "test";
    
        public static void main(String[] args) throws IOException {
            TestObjectSize testObjectSize = new TestObjectSize();
            // 打印对象的shallow size
            System.out.println("Shallow Size: " + MemoryUtil.memoryUsageOf(testObjectSize) + " bytes");
            // 打印对象的 retained size
            System.out.println("Retained Size: " + MemoryUtil.deepMemoryUsageOf(testObjectSize) + " bytes");
            System.in.read();
        }
    }

    开启指针压缩的情况

    结果如下:

    Shallow Size: 16 bytes
    Retained Size: 64 bytes
    
    

    MAT中的结果如下:

    img

    关闭指针压缩的情况

    结果如下:

    Shallow Size: 24 bytes
    Retained Size: 88 bytes
    
    

    MAT中的结果如下:

    img

    其他引用类型的大小

    根据上面的分析,可以计算出一个对象在内存中的占用空间大小情况,其他的引用类型可以参考分析计算过程来计算内存的占用情况。

    关于padding

    思考这样一个问题,是不是padding都加到对象的后面呢,如果对象头占12个字节,对象中只有1个long类型的变量,那么该long类型的变量的偏移起始地址是在12吗?用下面一段代码测试一下:

    @SuppressWarnings("ALL")
    public class PaddingTest {
    
        long a;
    
        private static Unsafe UNSAFE;
    
        static {
            try {
                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                theUnsafe.setAccessible(true);
                UNSAFE = (Unsafe) theUnsafe.get(null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) throws NoSuchFieldException {
            System.out.println(UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("a")));
        }
    
    }
    
    

    这里使用Unsafe类来查看变量的偏移地址,运行后结果如下:

    16
    
    

    如果是换成int类型的变量呢?结果是12。

    现在一般的CPU一次直接操作的数据可以到64位,也就是8个字节,那么字长就是64,而long类型本身就是占64位,如果这时偏移地址是12,那么需要分两次读取该数据,而如果偏移地址从16开始只需要通过一次读取即可。int类型的数据占用4个字节,所以可以从12开始。

    把上面的代码修改一下:

    @SuppressWarnings("ALL")
    public class PaddingTest {
    
        long a;
    
        byte b;
    
        byte c;
    
        private static Unsafe UNSAFE;
    
        static {
            try {
                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                theUnsafe.setAccessible(true);
                UNSAFE = (Unsafe) theUnsafe.get(null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) throws NoSuchFieldException {
            System.out.println(UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("a")));
            System.out.println(UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("b")));
            System.out.println(UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("c")));
        }
    
    }

    运行结果如下:

    16
    12
    13
    
    

    在本例中,如果变量的大小小于等于4个字节,那么在分配内存的时候会先优先分配,因为这样可以减少padding,比如这里的b和c变量;如果这时达到了16个字节,那么其他的变量按照类型所占内存的大小降序分配。

    再次修改代码:

    /**
     * VM options: -javaagent:D:\source-files\classmexer.jar
     */
    @SuppressWarnings("ALL")
    public class PaddingTest {
    
        boolean a;
        byte b;
    
        short c;
        char d;
    
        int e;
        float f;
    
        long g;
        double h;
    
        private static Unsafe UNSAFE;
    
        static {
            try {
                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                theUnsafe.setAccessible(true);
                UNSAFE = (Unsafe) theUnsafe.get(null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) throws NoSuchFieldException {
            System.out.println("field a --> "+ UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("a")));
            System.out.println("field b --> "+ UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("b")));
            System.out.println("field c --> "+ UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("c")));
            System.out.println("field d --> "+ UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("d")));
            System.out.println("field e --> "+ UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("e")));
            System.out.println("field f --> "+ UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("f")));
            System.out.println("field g --> "+ UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("g")));
            System.out.println("field h --> "+ UNSAFE.objectFieldOffset(PaddingTest.class.getDeclaredField("h")));
    
            PaddingTest paddingTest = new PaddingTest();
    
            System.out.println("Shallow Size: "+ MemoryUtil.memoryUsageOf(paddingTest));
            System.out.println("Retained Size: " + MemoryUtil.deepMemoryUsageOf(paddingTest));
        }
    
    }

    结果如下:

    field a --> 40
    field b --> 41
    field c --> 36
    field d --> 38
    field e --> 12
    field f --> 32
    field g --> 16
    field h --> 24
    Shallow Size: 48
    Retained Size: 48
    
    

    可以看到,先分配的是int类型的变量e,因为它正好是4个字节,其余的都是先从g和h变量开始分配的,因为这两个变量是long类型和double类型的,占64位,最后分配的是a和b,它们只占一个字节。

    如果分配到最后,这时字节数不是8的倍数,则需要padding。这里实际的大小是42字节,所以padding6字节,最终占用48字节。


    扩展

    jdk 有自带包 计算对象大小

    除了有些通用的工具类 如java8的jdk.nashorn.internal.ir.debug.ObjectSizeCalculator

    另外,如果要在代码中运行期动态获取一个对象的大小,可以多研究下 java.lang.instrument 这里的类,可以从加载类到创建,到运行具体的方法都有个比较确切的运行机制,有点偏向于JVM GC打的日志,目前个人还没研究透这方面,有需求的小伙伴可以交流或者issue

    相关属性在内存的偏移量

    ​ 可以UNSAFE.objectFieldOffset(Xxx.class.getDeclaredField("xFiled") 获取到该对象头后,相对的内存偏移量.

    展望

    其实内存分配及访问,也有可能涉及到cpu cache,路太长,先看看喵喵下

    参考:

    https://stackoverflow.com/questions/52353/in-java-what-is-the-best-way-to-determine-the-size-of-an-object

    展开全文
  • 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。 具体如下图 java 普通对象结构 java 数组对象结构 对象结构组成 对象头 ...

    概念

    在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

    具体如下图

    java 普通对象结构
    在这里插入图片描述

    java 数组对象结构
    在这里插入图片描述

    对象结构组成

    对象头

    HotSpot虚拟机的对象头包括两部分信息:

    1. Mark Word
      第一部分Mark Word,用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit
    2. 类型指针
      对象头的另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例.
    3. 数组长度(只有数组对象有)
      如果对象是一个数组, 那在对象头中还必须有一块数据用于记录数组长度.

    实例数据

    ​ 实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。

    对象引用(reference)类型在64位机器上,关闭指针压缩时占用8bytes, 开启时占用4bytes。

    原生类型(primitive type)的内存占用如下:

    Primitive TypeMemory Required(bytes)
    byte, boolean1 byte
    short, char2 bytes
    int, float4 bytes
    long, double8 bytes

    包装类型

    包装类(Boolean/Byte/Short/Character/Integer/Long/Double/Float)占用内存的大小等于对象头大小加上底层基础数据类型的大小。

    包装类型的对象内存占用情况如下:

    Numberic Wrappers+useCompressedOops-useCompressedOops
    Byte, Boolean16 bytes24 bytes
    Short, Character16 bytes24 bytes
    Integer, Float16 bytes24 bytes
    Long, Double24 bytes24 bytes

    对齐填充

    ​ 第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

    HotSpot的对齐方式为8字节对齐:

    (对象头 + 实例数据 + padding) % 8=0且0 <= padding < 8

    jvm相关参数

    上面用到的useCompressedOops这个参数,我们可以看看在命令行输入:java -XX:+PrintCommandLineFlags -version 查看jvm默认参数如图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pKMke0p9-1589680207000)(E:\技术帖子\笔记\基础\图\java对象结构\jvm参数.png)]

    分别是 -XX:+UseCompressedOops 和 -XX:+UseCompressedClassPointers
    这2个参数都是默认开启(+代表开启,-代表关闭)

    UseCompressedOops:普通对象指针压缩(oop是ordinary object pointer的缩写),
    UseCompressedClassPointers:类型指针压缩。

    例如:

    Object o = new Object();
    o指向new Object()的引用就是“普通对象指针”,
    new Object()自身还需要指向Object类型的引用,也就是"类型指针"。

    这2个压缩参数可以有4种组合(++, --, + -, -+),但有1种组合是会抛出警告的:

    -XX:+UseCompressedClassPointers -XX:-UseCompressedOops,不要使用这种参数组合,用这种参数启动jvm时会抛出警告。

    Java HotSpot(TM) 64-Bit Server TIM warning: UseCompressedClassPointers requires UseCompressOops
    

    原因是jvm层面的hotspot源码对jvm的参数组合做了限制,一看就懂:

    // UseCompressedOops must be on for UseCompressedClassPointers to be on.
    if (!UseCompressedOops){
       if (UseCompressedClassPointers){
       warning("UseCompressedClassPointers requires UseCompressOops");
    }
      FLAG_SET_DEFAULT(UseCompressedClassPointers , false);
    }
    

    HotSpot对象模型

    HotSpot中采用了OOP-Klass模型,它是描述Java对象实例的模型,它分为两部分:

    • 类被加载到内存时,就被封装成了klass,klass包含类的元数据信息,像类的方法、常量池这些信息都是存在klass里的,你可以认为它是java里面的java.lang.Class对象,记录了类的全部信息;

    • OOP(Ordinary Object Pointer)指的是普通对象指针,它包含MarkWord 和元数据指针,MarkWord用来存储当前指针指向的对象运行时的一些状态数据;元数据指针则指向klass,用来告诉你当前指针指向的对象是什么类型,也就是使用哪个类来创建出来的;

      那么为何要设计这样一个一分为二的对象模型呢?这是因为HotSopt JVM的设计者不想让每个对象中都含有一个vtable(虚函数表),所以就把对象模型拆成klass和oop,其中oop中不含有任何虚函数,而klass就含有虚函数表,可以进行method dispatch。

    HotSpot中,OOP-Klass实现的代码都在/hotspot/src/share/vm/oops/路径下,oop的实现为instanceOop 和 arrayOop,他们来描述对象头,其中arrayOop对象用于描述数组类型。

    以下就是oop.hhp文件中oopDesc的源码,可以看到两个变量_mark就是MarkWord,_metadata就是元数据指针,指向klass对象,这个指针压缩的是32位,未压缩的是64位;

    volatile markOop _mark;  //标识运行时数据
      union _metadata {
        Klass*      _klass;
        narrowKlass _compressed_klass;
      } _metadata;  //klass指针
    

    一个Java对象在内存中的布局可以连续分成两部分:instanceOop(继承自oop.hpp)和实例数据;

    如图:
    在这里插入图片描述

    通过栈帧中的对象引用reference找到Java堆中的对象,再通过对象的instanceOop中的元数据指针klass来找到方法区中的instanceKlass,从而确定该对象的类型。

    对象大小的计算

    有以下几点:

    1.在32位系统下,存放Class指针的空间大小是4字节,MarkWord是4字节,对象头为8字节。

    2.在64位系统下,存放Class指针的空间大小是8字节,MarkWord是8字节,对象头为16字节。

    3.64位开启指针压缩的情况下,存放Class指针的空间大小是4字节,MarkWord是8字节,对象头为12字节。

    4.数组长度4字节+数组对象头8字节(对象引用4字节(未开启指针压缩的64位为8字节)+数组markword为4字节(64位未开启指针压缩的为8字节))+对齐4=16字节。

    5.静态属性不算在对象大小内。

    贴网上的一个比较实用的工具类:

    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;  
    
    /** 
    
    ​	*对象占用字节大小工具类 
    
    ​    **/  
    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);  
    }  
    }
    

    最后举三个例子:

    首先需要创建一个mavean项目,引入包

    <dependency>
      <groupId>org.openjdk.jol</groupId>
      <artifactId>jol-core</artifactId>
      <version>0.9</version>
    </dependency>
    

    1.需要补齐的对象

    代码

    public class User {
        long sex;
        Long mobile;
        String name;
    
        public static void main(String[] args) {
            System.out.println(ClassLayout.parseInstance(new User()).toPrintable());
        }
    }
    

    输出如图
    在这里插入图片描述
    2.不需要padding补齐的对象

    代码:

    public class User {
    
        String name;
        Long mobile;
        int sex;
    
        public static void main(String[] args) {
            System.out.println(ClassLayout.parseInstance(new User()).toPrintable());
        }
    }
    

    输出如图
    在这里插入图片描述
    3.空对象,所占字节数

    代码:

    public class User {
    
        public static void main(String[] args) {
            System.out.println(ClassLayout.parseInstance(new User()).toPrintable());
        }
    }
    

    输出如图
    在这里插入图片描述
    4.数组对象结构

    代码:

    public class ArrayTest {
    
        public static void main(String[] args) {
            System.out.println(ClassLayout.parseInstance(new Integer[7]).toPrintable());
            System.out.println(ClassLayout.parseInstance(new Integer[8]).toPrintable());
            System.out.println(ClassLayout.parseInstance(new int[7]).toPrintabl![在这里插入图片描述](https://img-blog.csdnimg.cn/20200517102321457.png)e());
        }
    }
    

    输出如图
    在这里插入图片描述
    如果大家对java架构相关感兴趣,可以关注下面公众号,会持续更新java基础面试题, netty, spring boot,spring cloud等系列文章,一系列干货随时送达, 超神之路从此展开, BTAJ不再是梦想!

    架构殿堂

    展开全文
  • Java对象大小内幕浅析

    万次阅读 2016-03-29 18:59:00
    最近突发奇想,忽然对Java对象的内存大小感兴趣,去网上搜集了一些资料,并且做一下整理,希望能够各位帮助。  如果:你能算出new String(“abc”)这个对象在JVM中占用内存大小(64位JDK7中压缩大小48B,未压缩大小...

    欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


    欢迎跳转到本文的原文链接:https://honeypps.com/java/java-object-size-analysis/

     最近突发奇想,忽然对Java对象的内存大小感兴趣,去网上搜集了一些资料,并且做一下整理,希望能够各位帮助。
     如果:你能算出new String(“abc”)这个对象在JVM中占用内存大小(64位JDK7中压缩大小48B,未压缩大小64B), 那么看到这里就可以结束了~


    Java对象的内存布局:对象头(Header),实例数据(Instance Data)和对齐填充(Padding)
     虚拟机的对象头包括两部分信息,第一部分用于存储对象自身的运行时数据,如hashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。这部分数据的长度在32位和64的虚拟机(未开启指针压缩)中分别为4B和8B,官方称之为"Mark Word"。
     对象的另一部分是类型指针(klass),即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是那个类的实例。另外如果对象是一个Java数组,那再对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中却无法确定数组的大小。
    对象头在32位系统上占用8B,64位系统上占16B。 无论是32位系统还是64位系统,对象都采用8字节对齐。Java在64位模式下开启指针压缩,比32位模式下,头部会大4B(mark区域变为8B,kclass区域被压缩),如果没有开启指针压缩,头部会大8B(mark和kclass都是8B),换句话说,
     HotSpot的对齐方式为8字节对齐:(对象头+实例数据+padding)%8 等于0 且 0<=padding<8。以下说明都是以HotSpot为基准。


     在参考资料2中提到,再JDK5之后提供的java.lang.instrument.Instrumentation提供了丰富的对结构的等各方面的跟踪和对象大小的测量API。但是这个东西需要采用java的agent代理才能使用,至于agent代理和Instrumentation这里就不阐述了,我这里只阐述其使用方式。
     在参考资料3中提供了这个类,个人觉得很实用,代码如下所附1所示(代码比较长,索性就放到文章最后了):
     这段代码可以直接拷贝,然后将其打成jar包(命名为agent.jar,如果没有打包成功,可以直接下载博主打包好的),注意在META-INF/MANIFEST.MF中添加一行:

    Premain-Class: com.zzh.size.MySizeOf (注意":"后面的空格,否则会报错:invalid header field.)
    

     举个案例,代码如下(博主的系统是64位的,采用的是64位的JDK7):

    import com.zzh.size.MySizeOf;
    public class ObjectSize
    {
        public static void  main(String args[])
        {
            System.out.println(MySizeOf.sizeOf(new Object()));
        }
    }
    

     接下来进行编译运行,步骤如下:

    1. 编译(agent.jar放在当前目录下):javac -classpath agent.jar ObjectSize.java
    2. 运行:java -javaagent:agent.jar ObjectSize(输出结果:16,至于这个结果的分析,稍后再阐述)

     JDK6推出参数-XX:+UseCompressedOops,在32G内存一下默认会自动打开这个参数。可以在运行参数中添加-XX:-UseCompressedOops来关闭指针压缩。
     使用Instrumentation来测试对象的大小,只是为了更加形象的表示一个对象的大小,实际上当一个对象建立起来的时候可以手动计算其大小,代码案例实践用来证明理论知识的合理性及正确性,具体算法在下面的代码案例中有所体现。

    补充:原生类型(primitive type)的内存占用如下:

    Primitive TypeMemory Required(bytes)
    boolean1
    byte1
    short2
    char2
    int4
    float4
    long8
    double8

     引用类型在32位系统上每个占用4B, 在64位系统上每个占用8B。


    案例分析
     扯了这么多犊子,估计看的玄乎玄乎的,来几段代码案例来实践一下。

    案例1:上面的new Object()的大小为16B,这里再重申一下,博主测试机是64位的JDK7,如无特殊说明,默认开启指针压缩。

    new Object()的大小=对象头12B(8Bmak区,4Bkclass区)+padding的4B=16B
    

    案例2

        static class A{
            int a;
        }
        static class B{
            int a;
            int b;
        }
        public static void  main(String args[])
        {
            System.out.println(MySizeOf.sizeOf(new Integer(1)));
            System.out.println(MySizeOf.sizeOf(new A()));
            System.out.println(MySizeOf.sizeOf(new B()));
        }
    

    输出结果:

    (指针压缩) 16    16    24
    (指针未压缩)24    24    24
    

    分析1(指针压缩):

    new Integer(1)的大小=12B对象头+4B的实例数据+0B的填充=16B
    new A()的大小=12B对象头+4B的实例数据+0B的填充=16B
    new B()的大小=12B对象头+2*4B的实例数据=20B,填充之后=24B
    

    分析2(指针未压缩):

    new Integer(1)的大小=16B对象头+4B的实例数据+4B的填充=24B
    new A()的大小=16B对象头+4B的实例数据+4B的填充=24B
    new B()的大小=16B对象头+2*4B的实例数据+0B的填充=24B
    

    案例3

    System.out.println(MySizeOf.sizeOf(new int[2]));
    System.out.println(MySizeOf.sizeOf(new int[3]));
    System.out.println(MySizeOf.sizeOf(new char[2]));
    System.out.println(MySizeOf.sizeOf(new char[3]));
    

    输出结果:

    (指针压缩) 24    32    24    24
    (指针未压缩) 32    40    32    32
    

    分析1(指针压缩):

    new int[2]的大小=12B对象头+压缩情况下数组比普通对象多4B来存放长度+2*4B的int实例大小=24B
    new int[3]的大小=12B对象头+4B长度+3*4B的int实例大小=28B,填充4B =32B
    new char[2]的大小=12B对象头+4B长度+2*2B的实例大小=20B,填充4B=24B
    new char[3]的大小=12B对象头+4B长度+3*2B的实例大小+2B填充=24B
    (PS:new char[5]的大小=32B)
    

    分析2(指针未压缩):

    new int[2]的大小=16B对象头+未压缩情况下数组比普通对象多8B来存放长度+2*4B实例大小=32B
    new int[3]的大小=16B+8B+3*4B+4B填充=40B
    new char[2]的大小=16B+8B+2*2B+4B填充=32B
    new char[2]的大小=16B+8B+3*2B+2B填充=32B
    (PS:new char[5]的大小为40B)
    

    案例4(sizeOf只计算本体对象大小,fullSizeOf计算本体对象大小和引用的大小,具体可以翻阅附录1的代码).

    System.out.println(MySizeOf.sizeOf(new String("a")));
    System.out.println(MySizeOf.fullSizeOf(new String("a")));
    System.out.println(MySizeOf.fullSizeOf(new String("aaaaa")));
    

    输出结果:

    (指针压缩)24    48    56    
    (指针未压缩)32    64   72  
    

    分析1(指针压缩):

    翻看String(JDK7)的源码可以知道,String有这几个成员变量:(static变量属于类,不属于实例,所以声明为static的不计入对象的大小)
    
    private final char value[];
    private int hash;
    private transient int hash32 = 0;
    
    MySizeOf.sizeOf(new String("a"))的大小=12B对象头+2*4B(成员变量hash和hash32)+4B(压缩的value指针)=24B
    MySizeOf.fullSizeOf(new String("a"))的大小=12B对象头+2*4B(成员变量hash和hash32)+4B指针+(value数组的大小=12B对象头+4B数组长度+1*2B实例大小+6B填充=24B)=12B+8B+4B+24B=48B
    (PS: new String("aa"),new String("aaa"),new String("aaaa")的fullSizeOf大小都为48B)
    MySizeOf.fullSizeOf(new String("aaaaa"))的大小=12B+2*4B+4B+(12B+4B+5*2B+6B填充)=24B+32B=56B
    

    分析2(指针未压缩)

    MySizeOf.sizeOf(new String("a"))的大小=16B+2*4B+8B(位压缩的指针大小) =32B
    MySizeOf.fullSizeOf(new String("a"))的大小=16B对象头+2*4B(成员变量hash和hash32)+8B指针+(value数组的大小=16B对象头+8B数组长度+1*2B实例大小+6B填充=32B)=32B+32B=64B
    (PS: new String("aa"),new String("aaa"),new String("aaaa")的fullSizeOf大小都为64B)
    MySizeOf.fullSizeOf(new String("aaaaa"))的大小=16B+2*4B+8B+(16B+8B+5*2B+6B填充)=32B+40B=72B
    

     这些计算结果只会少不会多,因为在代码运行过程中,一些对象的头部会伸展,mark区域会引用一些外部的空间(轻量级锁,偏向锁,这里不展开),所以官方给出的说明也是,最少会占用多少字节,绝对不会说只占用多少字节。

    如果是32位的JDK,可以算一下或者运行一下上面各个案例的结果。

     看来上面的这些我们来手动计算下new String()的大小:

    1. 指针压缩的情况
    12B对象头+2*4B实例变量+4B指针+(12B对象头+4B数组长度大小+0B实例大小)=24B+16B=40B
    
    1. 指针未压缩的情况
    16B+2*4B+8B指针+(16B+8B数组长度大小+0B)=32B+24B=56B
    

     所以一个空的String对象最少也要占用40B的大小,所以大家在以后应该编码过程中要稍微注意下。其实也并不要太在意,相信能从文章开头看到这里的同学敲的代码也数以万计了,不在意这些也并没有什么不妥之处,只不过如果如果你了解了的话对于提升自己的逼格以及代码优化水平有很大的帮助,比如:能用基本类型的最好别用其包装类。

    附:agent.jar包源码

    package com.zzh.size;
    
    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;
    
    public class MySizeOf
    {
         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<>();  
                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);  
            }  
    }
    

    参考资料:
    1.《一个Java对象到底占多大内存?
    2.《如何精确地测量java对象的大小
    3.《一个对象占用多少字节?
    4.《深入理解Java虚拟机》周志明著。

    欢迎跳转到本文的原文链接:https://honeypps.com/java/java-object-size-analysis/

    欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


    展开全文
  • C++对象大小,你真的知道吗?

    千次阅读 多人点赞 2021-01-06 21:48:06
    我们都直到char大小为1,int为4,那么C++中对象大小是多少呢?
  • 计算对象大小又要考虑是普通对象还是数组对象,因为普通对象与数组对象的对象头存在些许差异。而且自JDK6以后,为了节省内存、提高运行效率,又引入了新的技术:指针压缩。更加剧了计算对象大小的难度。 这篇文章...
  • 两种计算Java对象大小的方法

    万次阅读 2017-01-10 20:41:24
    之前想研究一下unsafe类,碰巧在网上看到了这篇文章,觉得写得很好,就转载过来。...1. 对象头(_mark), 8个字节 2. Oop指针,如果是32G内存以下的,默认开启对象指针压缩,4个字节 3. 数据区 4.
  • java对象大小

    千次阅读 2016-08-10 00:14:16
    Java对象的内存布局:对象头(Header),实例数据(Instance Data)和对齐填充(Padding) 对象头在32位系统上占用8B,64位系统上占16B。 无论是32位系统还是64位系统,对象都采用8字节对齐。Java在64位模式下开启...
  • 初始化默认值以后,JVM要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象对象头Object Header之中。 这部分数据的...
  • 如何获取一个Java对象所占内存大小

    千次阅读 2021-02-26 12:51:59
    新建一个maven工程 ... } /** * 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小 * 注意:这个方法如果你看不懂也没关系,会用就行 * * @param objP * @return * @throws ...
  • 聊聊JVM(三)两种计算Java对象大小的方法

    万次阅读 多人点赞 2014-12-09 13:21:06
    这篇说说如何计算Java对象大小的方法。之前在聊聊高并发(四)Java对象的表示模型和运行时内存表示 这篇中已经说了Java对象的内存表示模型是Oop-Klass模型。 普通对象的结构如下,按64位机器的长度计算 1. 对象头(_...
  • Java对象内存大小计算

    万次阅读 多人点赞 2018-07-03 14:43:34
    最近在读《深入理解Java虚拟机》,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存? 在网上搜到了一篇博客讲的非常好:...
  • java-比较对象大小的方法

    千次阅读 2019-10-07 18:23:49
    一,基本数值类型(int ,char,short,long,float,double )对象大小比较可以直接使用比较运算符:> >= < <= == !=。 二,引用类型对象无法用数值去衡量其大小,故可使用(Object.equals ,...
  • 查询Oracle数据库段SEGMENT和对象大小

    万次阅读 2015-09-23 14:04:40
    查询Oracle数据库段SEGMENT和对象大小
  • 需求,打印输出员工的姓名,工号。并且对四名员工根据年龄...instanceof的作用是判断左边是否为右边一个类的实例,左边是对象,即向compareTo传进的参数是否是本类的一个实例化对象,是返回true,不是就返回false。
  • C# 能否获取一个对象所占内存的大小? 今日,在项目重构的时候忽然想到一个问题,一个类哪些成员的增加,会影响一个类所占内存的大小?C#有没有办法知道一个对象占多少内存呢? 第一个问题:很快想到是类的非静态...
  • 查看java对象占用了多少内存(对象大小),lucene为我们提供了一个很好的工具类
  • 前一篇文章《C++类对象大小的计算(一)常规类大小计算》初步介绍类大小计算后,我们继续来讨论含有虚函数时类的大小。 以下内存测试环境为Win7+VS2012,操作系统为32位 五、包含虚函数的类  包含虚函数的类...
  • 如何计算java对象大小

    千次阅读 2020-10-27 11:41:43
    如何计算一个对象大小
  • jmap 查看堆内对象占用空间大小详情

    千次阅读 2021-03-15 18:11:49
    jmap -histo PID 查看对内对象占用空间大小,有高到低排序 这里会生成一个类的统计报表,此表非常简单,如显示什么类有多少个实例,共占了多少字节等。如下: fs@inspur92:~/test/llxdata/081005/tmp$ jmap -histo ...
  • 如何计算Java对象所占内存的大小

    万次阅读 多人点赞 2018-05-24 11:42:12
    摘要:本文以如何计算Java对象占用内存大小为切入点,在讨论计算Java对象占用堆内存大小的方法的基础上,详细讨论了Java对象头格式并结合JDK源码对对象头中的协议字段做了介绍,涉及内存模型、锁原理、分代GC、OOP-...
  • JS获取对象长度大小

    万次阅读 2020-03-10 13:10:35
    /** * js对象无法直接通过.length来获取对象的长度大小。 * 获取方式: * var length = Object.keys(obj).length; */
  • java如何获取一个对象大小

    千次阅读 2019-09-25 13:21:51
    When---什么时候需要知道对象的内存大小 在内存足够用的情况下我们是不需要考虑java中一个对象所占内存大小的。但当一个系统的内存有限,或者某块程序代码允许使用的内存大小有限制,又或者设计一个缓存机制,当...
  • Java中对象大小

    千次阅读 2017-08-20 12:27:56
    Java中数据的类型分为8种基本类型和非基本类型,这里要说的就是非基本类型的Java对象大小
  • 怎么计算java对象大小

    千次阅读 2018-10-23 19:28:41
    本篇文章将想你介绍对象在内存中布局以及如何计算对象大小。 内存结构 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。如下图所...
  • C#计算对象占用内存大小(.net)

    千次阅读 2020-06-13 10:56:56
    对象大小 影响对象占用多大空间的主要因素如下: 1:字段个数 2:字段类型 3:字段布局 二.字段类型 先来看一下,主要数据类型在32位系统和64位系统中的字节长度: 从上面可以得知只有指针类型变成了8个字节,因为...
  • C++中如何计算类对象大小

    千次阅读 2018-10-20 16:05:07
    在学习到C++的类与对象时,我们又遇到了一个问题:如何计算类对象大小。 首先我们要知道什么是内存对齐 在C语言中,先来看一个例子: typedef struct { int a; short b; double c; }A; typedef ...
  • java 计算对象大小

    千次阅读 2018-09-17 10:16:31
    计算一个java对象大小,有助于了解一个程序在运行的时候,所需要的占用的内存的大小。那么如何才能知道一个java对象大小呢? **1.一个计算内存大小的工具** 下面首先了解一下,使用工具来计算java对象大小。...
  • //计算指定对象本身在堆空间的大小,单位字节 long byteCount = RamUsageEstimator.shallowSizeOf(obj); if (byteCount == 0) { return 0; } double oneMb = 1 * 1024 * 1024; if (byteCount ) { return 1;...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,690,662
精华内容 676,264
关键字:

对象大小

友情链接: KPCA故障检测.rar