首页 文章 精选 留言 我的

精选列表

搜索[情绪分析],共10000篇文章
优秀的个人博客,低调大师

Java技术专题-JVM研究系列(39)Java各种类型对象占用内存情况分析(上)

前言 只有当你到了一定层次,需要了解JVM内部运行机制,或者高并发多线程下,你写的代码对内存有影响,你想做性能优化。当你想深入了解java对象在内存中,如何存储,或者每个对象占用多大空间时。 内存公式 Java对象的内存布局=对象头(Header)+实例数据(Instance Data)+补齐填充(Padding)。 补齐填充 Java对象占用空间是8字节对齐的,即所有Java对象占用bytes数必须是8的倍数。 Shallow Size 对象自身占用的内存大小,不包括它引用的对象。 针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。当然这里面还会包括一些java语言特性的数据存储单元。 针对数组类型的对象,它的大小是数组元素对象的大小总和。 Retained Size Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C,C就是间接引用) 换句话说,Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存。 不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。 接下来用JProfiler验证: 新建一个空对象,观察空对象内存占用 public class TestObject {} 对象占用内存 16byte,如图: 结论 一般自建空对象占用内存 16Byte,16byte = 12Byte(Header) + 4Byte(Padding) 在TestObj中新增一个int属性,观察对象内存占用 public class TestObj { private int i; } 对象占用内存16byte,如图 结论 int 占用 4byte,16byte = 12byte(Header) + 4byte(int)+0byte(padding) 在TestObj中新增一个 long 属性,观察对象内存占用 public class TestObj { private long i; } 对象占用内存 24b,如图 结论 long 占用 8byte, 24byte = 12(Header) + 8(long) + 4(Padding) 其余基本类型可以参照以上自行验证,原理一样 包装类型占用 包装类(Boolean/Byte/Short/Character/Integer/Long/Double/Float)占用内存的大小 = 对象头大小 + 底层基础数据类型的大小。 包装类和其他引用类一样,会产生一个引用(reference) 在TestObj中新增一个Integer属性,观察对象内存占用 public class TestObj { private Integer i =128; } 对象占用内存 32b,如图 结论 Integer 占用16b, 32 = 12 (Header) + 16(Integer) + 4(reference) 特别的:-128~127在常量池,只占用4b,且不产生引用(reference) 在TestObj中新增一个 Long属性,观察对象内存占用 public class TestObj { private Long l = new Long(1); } 对象占用内存 40b,如图 结论 Long 占用 24b, 40 = 12 (Header) + 24(Long) + 4(reference) 其余包装类型可以参照以上自行验证,原理一样 基本类型数组占用 64位机器上,数组对象的对象头占用24 bytes,启用压缩后占用16字节。比普通对象占用内存多是因为需要额外的空间存储数组的长度(普通16b-12b)。 对象数组本身的大小=数组对象头 + length * 存放单个元素大小 在TestObj中新增一个 char[] 属性,观察对象内存占用 public class TestObj { private char[] c = {'a','b','c'}; } char[] c占用内存 40b,如图 结论 char[3] 占用 24b, 24 = 40 - 16,24 = 16(Header) + 3 * 2(char) + 2(Padding) 封装类型数组占用 封装类型数组比基本类型的数组,需要多管理元素的引用 对象数组本身的大小=数组对象头+length * 引用指针大小 + length * 存放单个元素大小。 在TestObj中新增一个 Integer[] 属性,观察对象内存占用。 public class TestObj { private Integer[] i = {128,129,130}; } Integer[] i占用内存 80b,如图 结论 Integer[3] 占用 80b, 80 = 96 - 16, 80 = 16(Header) + 3 * 4 (reference)+ 3 * 16(Integer) +4(padding) String占用内存 在TestObj中新增一个空String属性,观察对象内存占用。 public class TestObj { private String s = new String(""); } 对象占用内存 40b,如图 结论 String本身占用24byte,24=40-16,也就是说空"",也需要16byte。 注意 这里为什么要写String s = new String("")?请自己思考,不写会怎么样? 答:如果写成String s = “”,是不会再堆中开辟内存的,也就看不到String占用的空间,你看到的将会是下面的,至于为什么,都是因为final。

优秀的个人博客,低调大师

JPA,Spring中 Hibernate对JPA实现 如何初始化和获得数据源分析

通过调试,我们发现是 spring启动中,hibernate会装载和初始化 全局配置, 其实就是个 Map。 在Map中 他会初始化org.hibernate.cfg.AvailableSettings#DATASOURCE 的key 作为 map里数据源的key。 数据源初始化代码 位于 org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl#normalizeDataAccess : private void normalizeDataAccess( HashMap<?, ?> integrationSettingsCopy, MergedSettings mergedSettings, PersistenceUnitDescriptor persistenceUnit) { if ( dataSource != null ) { applyDataSource( dataSource, // we don't explicitly know null, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } if ( integrationSettingsCopy.containsKey( DATASOURCE ) ) { final Object dataSourceRef = integrationSettingsCopy.remove( DATASOURCE ); if ( dataSourceRef != null ) { applyDataSource( dataSourceRef, null, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } if ( integrationSettingsCopy.containsKey( JPA_JTA_DATASOURCE ) ) { final Object dataSourceRef = integrationSettingsCopy.remove( JPA_JTA_DATASOURCE ); if ( dataSourceRef != null ) { applyDataSource( dataSourceRef, true, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } if ( integrationSettingsCopy.containsKey( JPA_NON_JTA_DATASOURCE ) ) { final Object dataSourceRef = integrationSettingsCopy.remove( JPA_NON_JTA_DATASOURCE ); applyDataSource( dataSourceRef, false, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } if ( integrationSettingsCopy.containsKey( URL ) ) { // these have precedence over the JPA ones final Object integrationJdbcUrl = integrationSettingsCopy.get( URL ); if ( integrationJdbcUrl != null ) { //noinspection unchecked applyJdbcSettings( integrationJdbcUrl, NullnessHelper.coalesceSuppliedValues( () -> ConfigurationHelper.getString( DRIVER, integrationSettingsCopy ), () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, integrationSettingsCopy ), () -> ConfigurationHelper.getString( DRIVER, mergedSettings.configurationValues ), () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, mergedSettings.configurationValues ) ), integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } if ( integrationSettingsCopy.containsKey( JPA_JDBC_URL ) ) { final Object integrationJdbcUrl = integrationSettingsCopy.get( JPA_JDBC_URL ); if ( integrationJdbcUrl != null ) { //noinspection unchecked applyJdbcSettings( integrationJdbcUrl, NullnessHelper.coalesceSuppliedValues( () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, integrationSettingsCopy ), () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, mergedSettings.configurationValues ) ), integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } if ( persistenceUnit.getJtaDataSource() != null ) { applyDataSource( persistenceUnit.getJtaDataSource(), true, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } if ( persistenceUnit.getNonJtaDataSource() != null ) { applyDataSource( persistenceUnit.getNonJtaDataSource(), false, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } if ( mergedSettings.configurationValues.containsKey( URL ) ) { final Object url = mergedSettings.configurationValues.get( URL ); if ( url != null && ( ! ( url instanceof String ) || StringHelper.isNotEmpty( (String) url ) ) ) { applyJdbcSettings( url, ConfigurationHelper.getString( DRIVER, mergedSettings.configurationValues ), integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } if ( mergedSettings.configurationValues.containsKey( JPA_JDBC_URL ) ) { final Object url = mergedSettings.configurationValues.get( JPA_JDBC_URL ); if ( url != null && ( ! ( url instanceof String ) || StringHelper.isNotEmpty( (String) url ) ) ) { applyJdbcSettings( url, ConfigurationHelper.getString( JPA_JDBC_DRIVER, mergedSettings.configurationValues ), integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } // any other conditions to account for? } 通过代码可以看出 他会优先几个 key,看是否已经有了,有就沿用这些key里的数据源。 我的项目目前都没有,代码往下走,到了 if ( persistenceUnit.getNonJtaDataSource() != null ) { 这一行, 发现在 org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor#getNonJtaDataSource 获取了数据源: 转而调用了javax.persistence.spi.PersistenceUnitInfo#getNonJtaDataSource : 发现真正的实现类是:org.springframework.orm.jpa.persistenceunit.SpringPersistenceUnitInfo 的getNonJtaDataSource 方法。 然后最终调用了 :org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo#getNonJtaDataSource 这个方法返回了 这个类的实例变量 org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo#nonJtaDataSource , 所以我们继续看 实例变量是如何初始化的: 最终发现 是org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration 初始化的, 而他是由org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration 导入的。 然后发现 最后DataSource来自于 spring boot autoconfig包的org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration 类, HibernateJpaConfiguration 直接继承的他, 默认的DataSource对象也是JpaBaseConfiguration 实例字段。 org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#dataSource 而这个字段则是直接通过 类构造方法 让spring自动ioc的。 题外话:关于 JPA实现类似mybatis的动态效果,可以参考下大佬的开源: https://gitee.com/it00021hot/fenix

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册