热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

数据库数据在Java占用内存简单估算

数据库数据在Java占用内存简单估算结论:1.数据库记录放在JAVA里,用对象(ORM一般的处理方式)需要4倍左右的内存空间,用HashMap这种KV保存需要10倍空间;2.如果你主要数据是text大文本,那空间一般可以按2倍估算。以上是一个通用数据测试结论,估大家参考

数据库数据在Java占用内存简单估算 结论: 1.数据库记录放在JAVA里,用对象(ORM一般的处理方式)需要4倍左右的内存空间,用HashMap这种KV保存需要10倍空间; 2.如果你主要数据是text大文本,那空间一般可以按2倍估算。 以上是一个通用数据测试结论,估大家参考

数据库数据在Java占用内存简单估算

结论:

1.数据库记录放在JAVA里,用对象(ORM一般的处理方式)需要4倍左右的内存空间,用HashMap这种KV保存需要10倍空间;

2.如果你主要数据是text大文本,那空间一般可以按2倍估算。

以上是一个通用数据测试结论,估大家参考。

数据库记录占用的空间大小比较好算,比如一个int占用4字节,bigint占用8字节,date占用3字节,datetime占用8字节,varchar是变长字节等。如果不想精确计算,在数据库中通过统计信息也可以比较轻松的知道表总共占用的空间及每条记录平均行长。

当我们用JDBC访问数据库时,经常会被问到内存溢出的问题,由于java是面向对象的语言,用JVM来自动内存回收,不能按普通方法计算内存,本文给出一个估算内存的思路和参考答案

先给出普通JDBC中数据库对象与内存的映射关系

MySQL

Oracle

JDBC

Int

Integer

Int unsigned

Long

BigInt

Long

BigInt unsigned

BigInteger

Decimal

Number

BigDecimal

Varchar

Varchar2

String

Date

Date

Datetime

Date

Timestamp

Timestamp

Timestamp

Timestamp

Clob

Clob

String

Blob

blob

Byte[]

Text

Clob

String

float

binary_float

float

double

binary_double

double

上面这个比较好理解,接下来我们需要JAVA常用对象的内存占用空间,这个可以通过JDK 5 开始提供的Instrumentation 接口来完成,也可以通过开源的sizeOf.jar 来测试,笔者是通过sizeOf.jar验证的。测试结果数据如下:

对象

64位 JVM 压缩指针

 64位 JVM 非压缩指针

Integer

16

24

Long

24

24

Object

16

16

Date

24

32

Timestamp

32

40

String_0

48

64

String_1

56

72

String_10

72

88

String_100

248

264

StringBuilder

24

32

BigDecimal

40

48

BigInteger

64

80

HashMap

128

216

HashMap_0

72

96

HashMap_100

576

1112

HashMap_10000

65600

131160

ArrayList

80

144

ArrayList_0

40

64

ArrayList_100

440

864

ArrayList_10000

40040

80064

LinkedList

48

80

LinkedHashMap

96

144

ClassA

32

40

ClassB

40

48

ClassC

40

56

由于现在主机一般都是64位, 64位JVM从JDK1.6.45开始,当JVM最大内存小于32GB时,自动打开压缩指针特性,这样对象的内存占用空间少很多,由上表可以看出,至少减少1/3的空间。

下面我们结合数据库数据来测试

假如mysql数据库有一张emp表,结构如下:

CREATE TABLE `emp` (
  `id` int(11) NOT NULL,
  `create_time` datetime DEFAULT NULL,
  `modify_time` datetime DEFAULT NULL,
  `name` varchar(16) DEFAULT NULL,
  `address` varchar(256) DEFAULT NULL,
  `age` smallint(6) DEFAULT NULL,
  `height` decimal(10,2) DEFAULT NULL,
  `weight` decimal(10,2) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

样本数据如下:

hm.put("id", 1988);
hm.put("createTime", new Date());
hm.put("modifyTime", new Date());
hm.put("name", "张三丰");
hm.put("address","浙江杭州市西湖大道188号808室");
hm.put("age",88);
hm.put("weight",new BigDecimal(88));
hm.put("height",new BigDecimal(188));
hm.put("phone","1388888888");

按上面样本数据计算,有效数据约80字节,在MySQL里占用空间约120字节

在java里转换为HashMap和Emp对象测试空间如下

对象

64位 JVM 压缩指针

 64位 JVM 非压缩指针

HashMap_empty

128

216

HashMap_full

1360

1832

Emp_empty

72

112

Emp_full

464

600

从上面测试结果看,数据到JAVA里占用的空间增加了许多,在64位压缩指针下,如果存到HashMap,需要1360字节,空间是数据库约11.3倍,如果存为Emp普通对象,需要464字节,是数据库的3.8倍。

如果我们是一个分页从数据库读取emp信息,每页显示50条记录,用List保存,HashMap需要68KB,emp对象需要23KB。

根据这个简单测试,我们可以总结一个结论:

数据库记录放在JAVA里,用对象(ORM一般的处理方式)需要4倍左右的内存空间,用HashMap这种KV保存需要10倍空间。

如果你的数据和参考数据差异非常大,如主要数据text大文本,那空间一般可以简单的按2倍估算。

以上是一个通用数据测试结论,估大家参考。

下面是测试代码:

import net.sourceforge.sizeof.SizeOf;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.*;

public class TestSize {
    static {
        SizeOf.skipStaticField(true); //java.sizeOf will not compute static fields
        //SizeOf.skipFinalField(true); //java.sizeOf will not compute final fields
        //SizeOf.skipFlyweightObject(true); //java.sizeOf will not compute well-known flyweight objects
    }
    public static void main(String[] args) throws SQLException, IOException, IllegalAccessException {
        TestSize ts=new TestSize();
        ts.testObjectSize();
        ts.testDataSize();
        System.out.println("ok");
    }

    public void testObjectSize() {
        System.out.println("Integer:"+SizeOf.deepSizeOf(new Integer(56)));
        System.out.println("Long:"+SizeOf.sizeOf(new Long(56L)));
        System.out.println("Object:"+SizeOf.sizeOf(new Object()));
        System.out.println("Date:"+SizeOf.sizeOf(new Date()));
        System.out.println("Timestamp:"+SizeOf.sizeOf(new Timestamp(System.currentTimeMillis())));
        System.out.println("String_0:"+SizeOf.deepSizeOf(new String()));
        System.out.println("String_1:"+SizeOf.deepSizeOf(new String("1")));
        System.out.println("String_10:"+SizeOf.deepSizeOf(new String("0123456789")));
        System.out.println("String_100:"+SizeOf.deepSizeOf("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"));
        System.out.println("StringBuilder:"+SizeOf.deepSizeOf(new StringBuilder()));
        System.out.println("BigDecimal:"+SizeOf.deepSizeOf(new BigDecimal("34535643.23")));
        System.out.println("BigInteger:"+SizeOf.deepSizeOf(new BigInteger("34535643")));
        System.out.println("HashMap:"+SizeOf.deepSizeOf(new HashMap()));
        System.out.println("HashMap_0:"+SizeOf.deepSizeOf(new HashMap(0)));
        System.out.println("HashMap_100:"+SizeOf.deepSizeOf(new HashMap(100)));
        System.out.println("HashMap_10000:" + SizeOf.deepSizeOf(new HashMap(10000)));
        System.out.println("ArrayList:"+SizeOf.deepSizeOf(new ArrayList()));
        System.out.println("ArrayList_0:"+SizeOf.deepSizeOf(new ArrayList(0)));
        System.out.println("ArrayList_100:"+SizeOf.deepSizeOf(new ArrayList(100)));
        System.out.println("ArrayList_10000:"+SizeOf.deepSizeOf(new ArrayList(10000)));
        System.out.println("LinkedList:"+SizeOf.deepSizeOf(new LinkedList()));
        System.out.println("LinkedHashMap:"+SizeOf.deepSizeOf(new LinkedHashMap()));

        System.out.println("ClassA:" + SizeOf.deepSizeOf(new ClassA()));
        System.out.println("ClassB:"+SizeOf.deepSizeOf(new ClassB()));
        System.out.println("ClassC:"+SizeOf.deepSizeOf(new ClassC()));

    }
    public void testDataSize() throws IOException, IllegalAccessException {
        HashMap hm=new HashMap();
        System.out.println("HashMap_empty:"+SizeOf.deepSizeOf(hm));
        hm.put("id", 1988);
        hm.put("createTime", new Date());
        hm.put("modifyTime", new Date());
        hm.put("name", "张三丰");
        hm.put("address","浙江杭州市西湖大道188号808室");
        hm.put("age",88);
        hm.put("weight",new BigDecimal(88));
        hm.put("height",new BigDecimal(188));
        hm.put("phone","1388888888");
        System.out.println("HashMap_full:" + SizeOf.deepSizeOf(hm));
        Emp emp=new Emp();
        System.out.println("Emp_empty:"+SizeOf.deepSizeOf(emp));
        emp.setId(1988);
        emp.setCreateTime(new Timestamp(System.currentTimeMillis()));
        emp.setModifyTime(new Timestamp(System.currentTimeMillis()));
        emp.setName("张三丰");
        emp.setAddress("浙江杭州市西湖大道188号808室");
        emp.setAge(28);
        emp.setWeight(new BigDecimal("88"));
        emp.setHeight(new BigDecimal("188"));
        emp.setPhone("13888888888");
        System.out.println("Emp_full:"+SizeOf.deepSizeOf(emp));
    }
    class ClassA{
    }
    class ClassB extends  ClassA{
    }
    class ClassC extends  ClassB{
    }
    class Emp{
        private Integer id;
        private Timestamp createTime;
        private Timestamp modifyTime;
        private String name;
        private String address;
        private Integer age;
        private BigDecimal height;
        private BigDecimal weight;
        private String phone;

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public Timestamp getCreateTime() {
            return createTime;
        }

        public void setCreateTime(Timestamp createTime) {
            this.createTime = createTime;
        }

        public Timestamp getModifyTime() {
            return modifyTime;
        }

        public void setModifyTime(Timestamp modifyTime) {
            this.modifyTime = modifyTime;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        public BigDecimal getHeight() {
            return height;
        }

        public void setHeight(BigDecimal height) {
            this.height = height;
        }

        public BigDecimal getWeight() {
            return weight;
        }

        public void setWeight(BigDecimal weight) {
            this.weight = weight;
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phOne= phone;
        }
    }
}

推荐阅读
  • 在数据分析工作中,我们通常会遇到这样的问题,一个业务部门由若干业务组构成,需要筛选出每个业务组里业绩前N名的业务员。这其实是一个分组排序的 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 本文由编程笔记小编整理,介绍了PHP中的MySQL函数库及其常用函数,包括mysql_connect、mysql_error、mysql_select_db、mysql_query、mysql_affected_row、mysql_close等。希望对读者有一定的参考价值。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • MyBatis错题分析解析及注意事项
    本文对MyBatis的错题进行了分析和解析,同时介绍了使用MyBatis时需要注意的一些事项,如resultMap的使用、SqlSession和SqlSessionFactory的获取方式、动态SQL中的else元素和when元素的使用、resource属性和url属性的配置方式、typeAliases的使用方法等。同时还指出了在属性名与查询字段名不一致时需要使用resultMap进行结果映射,而不能使用resultType。 ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
author-avatar
pilishen
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有