`

讨论关于Java占用内存的研究

    博客分类:
  • JAVA
阅读更多

最近对程序占用内存方面做了一些优化,取得了不错的效果,总结了一些经验,简要说一下,相信会对大家写出优质的程序有所帮助。下面的论述针对32位系统,对64位系统不适用,后叙。

  经常你写了一个程序,一测试,功能没问题,一看内存占用也不多,就不去考虑其它的东西了。但可能程序使用了一个什么数据结构,会当数据规模变大时,内存占用激增。

  基本&&关键的问题是,Java里各种东东占多少内存?????????

  对于primitive类型,有8个

  byte short int long float double char boolean 它们的长度分别是

  1 2 4 8 4 8 2 1

  这个不罗嗦了,举例来说

  long[] data=new long[1000];

  占用内存 8*1000 bytes

  此外,data本身是一个Object,也占用内存若干,后叙,当然它针对 8*1000来说,忽略不计,再说Object的占用,在说这个之前,先说说引用,一惯的说法是Java里没有指针了,只有引用,引用是安全的。这个说法 没错,但是从机理上来说,引用就是指针,只是jvm对指针的使用检查和限制很多,这个引用/指针变得很安全。直接来结论:一个引用占4byte ,在32位系统上

  Object obj=null; //4byte

  Object[] objs=new Object[1000]; //至少4*1000byte

  你看我定义了一个 obj,还是null,就占4byte

  定义了一个 objs,1000个元素,但都是null啊,就都每个占4byte

  是的!!!!!

  虽然obj==null,但它已经是 一个引用,或者说一个指针了

  指针也要占地方啊!!!!啊!!!!啊!!!!

  接下来,直接给另一个结论: Object占8byte,注意,纯Object

  Object obj=new Object(); //多少????

  8byte?? 错!! 12byte,忘了还有一个引用,8byte是Object的内容

  记住 Object obj=new Object(); 占12byte

  Object[] objs=new Object[1000];

  for(int i=0;i<1000;i++) {

  objs[i]=new Object();

  }

  至少占用 12*1000 bytes

  推论: Object占12bytes,似乎和上面的结论矛盾??!!

  没有!! 不管Object,没有被垃圾回收之前,总得被别人引用吧?

  总的有指针指它吧? 既然指,那个引用or指针就要占地方啊 4byte

  加起来是12byte,反正一个Object至少 12bytes

  还是直接给结论,推导的过程我就都包办了,咱不是脏活累活抢着干么!!

  一个Integer占 16 bytes

  这时您可能会有疑问,Integer=Object+int,就是:

  public class Integer {

  public int value;

  }

  Integer应该占 8+4=12 bytes啊

  你说的有道理,但是jvm对所有的Object有限制!!

  这个限制被我发现了,就是不管什么Object占的空间,要是8的倍数

  12不是8的倍数,只能是16了!!!

  推论:Byte也占16bytes!!!!!!!!!!!

  问:

  Byte[] bytes=new Byte[1000];

  占用空间多少?

  答: 约为(至少为) (16+4)*1000 bytes

  好家伙!!!!!!!!

  论题:数组空间占用怎么算?

  我这里直接给结论了,推导这个花了更长的时间:

  对于数组来说,数组这个Object有一个length属性,数组的元素相当于其成员

  public class Array {

  public int length;

  //... 其它成员

  }

对于数组,我们不是直接可以取length属性么,源于此

  public byte[] bytes=new byte[1000];

  System.out.println(bytes.length); // 看,有length属性

  上面的bytes换算过来是:

  public class Array {

  public int length;

  public byte byte0;

  public byte byte1;

  ...

  public byte byte999;

  }

  上面的bytes占用的内存是:

  4+[8+4 + 1*1000] = 4+ [1012]=4+1016=1020

  4是 bytes这个引用,8是Object基占的,4是length属性占的

  1000是1000个成员占的,本来是 1012,但要求是8的倍数,变成 1016了

  总共是 1020

  再如:

  byte[] bytes=new byte[4];

  的内存占用是:

  4+[8+4+4*1]=4+[16]=20;

  byte[] bytes=new byte[3]; 也是 20

  对于元素是Object的数组,Object也是当作其成员,(注意只有引用这个数组的空间,这个可以推到普通Class上)

  Byte[] bytes=new Byte[1000];

  这个 bytes的定义相当于:

  public class Array {

  public int length;

  public Byte byte0;

  .....

  public Byte byte999;

  }

  占用空间是:

  4+[8+4+4*1000]+16*1000= 4+ 4016 + 16000 = 你自己算吧

  推论:千万不要用 Byte[] 有20倍的差距!!!!!!!

  你可能一下子没明白过来,没关系多琢磨一下,对于普通的class来说,内容占用就是基加成员的占用,Object成员只记引用

  public class Abc {

  public int n;

  public byte b;

  public Object obj;

  }

  它的内容占用是: [8+4+1+4]=24

  所以 Abc one=new Abc()的占用是 4+24=28

  提醒:对于 Abc的成员 obj没有计,如果要计入的话,循环这个过程就可以了。(琢磨一下)

  举例:

  public class Abc {

  public byte b;

  public Object obj=null;

  }

  public class Def {

  public int n;

  public byte b;

  public Abc obj=new Abc();

  }

  问:

  Def one=new Def(); //占多少?

  答:

  4+[8+4+1+4]+[8+1+4]=4+24+16=44

  public class Abc {

  public byte b;

  public Object obj=null;

  }

  public class Def {

  public int n;

  public byte b;

  public Abc[] objs=new Abc[100];

  {

  for(int i=0;i<10;i++) {

  objs[i]=new Abc();

  }

  }

  }

  问:

  Def one=new Def(); //占多少?

  答:

  kao,一下我也算不出来,不过我写了程序,可以算出来,你给它一个Object,它就能递归的算出总共占了多少内存,这个程序不复杂,你也可以写出来。我等机会合适了再放出。

  单独说一下String,String的结构是:

  public class String {

  private final char value[];

  private final int offset;

  private final int count;

  private int hash; // Default to 0

  }

  所以,不考虑那个char[]的占用,一个String最少占用 [8+4+4+4+4]=24bytes

  加上引用,共28bytes,所以

  String s="";

  占用28bytes!!!!! 尽管它的长度为0

  如果精确的算,加上引用一个String的占用是

  4+24+[8+4+2*length]

  String s=""; 的占用是 28+16= 44

  String s="ab" 的占用是 28+16= 44

  String s="abc" 的占用是 28+24 = 52

  要说的是,String是常用的类,这么看,String耗内存很多,所以jvm有优化,同样的内容尽量重用,所以除了28是必须的外,那个char[] 很可能一样

  比方说

  String[] s=new String[1000];

  for(int i=0;i<1000;i++) {

  s[i]=new String("abcdefasdjflksadjflkasdfj");

  }

  的占用的数量级是 28*1000,那 1000个字符串本身基本上不占内存,只有一份!!!!!!

  反正String 至少是 28,最多也可能是28!!!!!!!!

  比较占内存的数据结构,这个很重要:

  基本上就是 primitive的包装

  实例:

  我以前用一个

  Hashtable的结构,有100万个元素

  改为String[]+int[]后,内存占用改观不少,速度也很快

  100万的String[] 快排一下,也就2秒多,查找用2分,和hash也差不多少

分享到:
评论

相关推荐

    快速、简洁、解决大文件内存溢出的java处理Excel工具 .rar

    前言 最近有个项目在生产环境做数据导入时,发现开始执行导入任务会出现cpu狂飙的情况。几番定位查找发现是在...这种方式POI会把文件的所有内容都加载到内存中,读取大的excel文件时很容易占用大量内存导致oom的发生

    Java聊天室程序源码(毕业设计)

    本文讨论了如何利用java技术开发聊天室系统,基本满足了结构化、界面友好、速度快、安全性以及稳定性等特点。 系统着重研究并实现了网络应用的部分。根据实现的情况看,具有较友好的聊天界面生成效果,以及流畅的...

    操作系统(内存管理)

    在讨论分配内存之前,我们将先讨论释放,因为它更简单。为了释放内存,我们必须要做的惟一一件事情就是,获得我们给出的指针,回退 sizeof(struct mem_control_block) 个字节,并将其标记为可用的。这里是对应的代码...

    java的传值与传引用详解

     简单的说,引用其实就像是一个对象的名字或者别名 (alias),一个对象在内存中会请求一块空间来保存数据,根据对象的大小,它可能需要占用的空间大小也不等。访问对象的时候,我们不会直接是访问对象在内存中的数据...

    Tomcat内存溢出的三种情况及解决办法分析

    这500M内存中的一部分必须用于系统dll的加载,那么真正剩下的也许只有400M,现在关键的地方出现了:当你使用Java创建一个线程,在JVM的内存里也会创建一个Thread对象,但是同时也会在操作系统里创建一个真正的物理...

    Java经典入门教程pdf完整版

    传说有天,几位Java成员组的会员正在讨论给这个新的语言取什么名字,当时他们止在 咖啡馆喝着Java(爪哇)咖啡,有一个人灵机一动说就叫Java怎杵,得到了其他人的赞同, 于是,Java这个名字就这样传开了。当然对于传说,了解...

    讨论字符串中字符出现的次数

    整型数组中的元素,获取其元素并不困难。...我认为:因为字符串的本身属性,对其进行处理时,占用大量内存。如何寻找更好更快捷的方法才是努力的方向。下面是我的一个程序举例,分别对单个字符、连续字符进行求次数。

    JDK10官方包64位(Windows)

    允许 HotSpot 虚拟机在备用内存设备上分配 Java 对象堆  JEP 317: 基于 Java 的 JIT 编译器(试验版本)  JEP 319: 根证书。开源 Java SE Root CA 程序中的根证书  JEP 322: 基于时间的版本发布模式。“Feature ...

    JavaScript 垃圾回收机制分析

    在公司经常会听到大牛们讨论时说道内存泄露神马的,每每都惊羡不已,最近精力主要用在了Web 开发上,读了一下《JavaScript高级程序设计》(书名很唬人,实际作者写的特别好,由浅入深)了解了一下JavaScript垃圾回收...

    新版Android开发教程.rar

    � 采用了对有限内存、电池和 CPU 优化过的虚拟机 Dalvik , Android 的运行速度比想象的要快很多。 � 运营商(中国移动等)的大力支持,产业链条的热捧。 � 良好的盈利模式( 3/7 开),产业链条的各方:运营商、...

    lunar-unity-console:使用本机平台UI构建的高性能Unity iOSAndroidAndroid记录器

    具有低内存占用量的本机C / Objective-C / Java代码。 适用于大量日志(最多65536个条目)。 完全使用本机iOS / Android UI构建(不依赖Unity GUI)。 独立于分辨率(在高分辨率/视网膜显示器上看起来不错)。 ...

    javaee案例开发源码-micronaut-camunda-bpm:Micronaut和Camunda(工作流引擎)之间的集成。我们使用合理

    流程引擎以最小的内存占用嵌入到您的应用程序中。 集成预先配置了合理的默认值,因此您可以以最少的配置开始:只需在您的 Micronaut 项目中添加一个依赖项! 我们不知道我们的开源项目的所有安装。 然而,我们爱 ...

    asp.net知识库

    .NET关于string转换的一个小Bug Regular Expressions 完整的在.net后台执行javascript脚本集合 ASP.NET 中的正则表达式 常用的匹配正则表达式和实例 经典正则表达式 delegate vs. event 我是谁?[C#] 表达式计算引擎...

    sesvc.exe 阿萨德

    本篇主要想讨论 ConcurrentHashMap 这样一个并发容器,在正式开始之前我觉得有必要谈谈 HashMap,没有它就不会有后面的 ConcurrentHashMap。 HashMap 众所周知 HashMap 底层是基于 数组 + 链表 组成的,不过在 jdk...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    mssql 微软 只能能运行在windows平台,体积比较庞大,占用许多系统资源, 但使用很方便,支持命令和图形化管理,收费。 中型企业 Mysql 甲骨文 是个开源的数据库server,可运行在多种平台, 特点是响应速度特别快,...

Global site tag (gtag.js) - Google Analytics