`

讨论关于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虚拟内存研究

    ### Java虚拟内存研究 #### 内存溢出的分析与解决方法 在现代软件开发中,尤其是使用Java语言开发的企业级应用中,内存管理和优化是一个非常关键的技术领域。内存溢出(Out Of Memory, OOM)是导致Java应用程序...

    JAVA技巧(Java多线程运行时,减少内存占用量).pdf

    根据提供的文件内容,该文件主要讨论了在Java多线程环境下如何减少内存占用量。文件内容并不完整,且存在 OCR 扫描错误,但我会尝试从中提取与Java多线程和内存管理相关的知识点,并加以详细解释。 ### Java多线程...

    从 Java 代码到 Java 堆 理解和优化您的应用程序的内存使用

    通过分析Java代码中的内存开销,以及讨论对象创建、集合效率等方面,将揭示如何确定性能瓶颈并改进代码。 【标签】:优化内存,Java内存管理,Java堆,对象创建,集合效率 【正文】: Java应用程序的内存管理是一个...

    JAVA进程占用高内存缘由分析与优化方法_.docx

    在 Java 进程中,高内存占用是一个常见的问题,本文将通过 jmap 和 ps 命令来分析 Java 进程的内存占用情况,并讨论可能的优化方法。 1. Java 进程的内存占用分析 使用 jmap 命令可以查看 Java 进程的内存占用情况...

    Java内存泄露及内存无法回收解决方案

    Java内存管理是编程中至关重要的一个环节,尤其是对于大型、长时间运行的应用来说,内存泄漏和内存无法回收可能导致系统性能下降,甚至导致系统崩溃。本文将深入探讨Java内存泄露的原理,分析内存无法回收的原因,并...

    JAVA 内存设置原理

    GC是JVM自动管理内存的重要机制,其主要目的是回收不再使用的对象占用的内存空间。根据不同的场景和需求,JVM提供了多种GC算法: - **Serial Collector**:单线程收集器,适用于单核处理器的服务器或桌面应用。 - *...

    关于static的小结(Java内存溢出)

    ### 关于static的小结(Java内存溢出) #### 标题和描述中的知识点 在《关于static的小结(Java内存溢出)》这篇文章中,作者主要探讨了与Java中的`static`关键字相关的知识点,以及如何可能导致内存溢出的情况。...

    如何解决Java内存泄漏.pdf

    本文将深入讨论Java内存泄漏的解决方法,提供一些工具和技巧,帮助开发者检测和解决内存泄漏问题。 首先,需要了解什么是内存泄漏。在Java中,内存泄漏通常是指不再使用的对象占用的内存无法被垃圾回收器回收。这种...

    Java加载dll,导致Java进程内存泄露

    即使Java对象被垃圾收集,本地对象仍然占用内存。 2. **全局引用管理不当**:Java中的`GlobalRef`用于保持对本地对象的长期引用,即使Java对象已经被垃圾收集。如果不正确地管理和释放全局引用,内存泄漏就会发生。...

    java内存讲解

    本文将详细探讨JVM的垃圾回收机制及其调优方法,深入分析Java内存分配原理,并讨论Java中的内存管理与内存泄露问题。 #### 二、JVM的垃圾回收机制概述 垃圾回收(Garbage Collection, GC)是JVM用于自动回收不再使用...

    JAVA程序内存泄漏综述

    本文重点讨论Java内存泄漏问题,并将其与C/C++的内存泄漏进行对比分析。 C/C++程序在运行时通过`new/malloc`等命令分配内存,而`delete/free`等命令则负责释放内存。这种手动管理内存的方式容易导致内存泄漏——即...

    MAT Java内存分析工具

    MAT(Memory Analyzer Tool)是Eclipse基金会开发的一款强大的Java内存分析工具,专为解决Java应用程序的内存泄漏和性能优化问题而设计。它提供了丰富的功能,包括堆dump分析、对象引用链追踪、内存消耗报告等,使得...

    Java内存模型中的三个代

    在讨论Java内存模型时,还涉及到了虚拟内存的概念。虚拟内存是指在JVM启动时保留的一部分内存,这部分内存不一定全部被JVM使用,但它保证了不会被其他进程占用。初始堆内存和最大堆内存分别由-Xms和-Xmx参数控制,而...

    基于java的移动通讯技术研究

    8. **性能优化**:由于移动设备资源有限,Java开发者需要关注代码优化,如减少内存占用、提高运行效率,确保应用在低功耗设备上也能流畅运行。 论文《基于Java的移动通讯技术研究》可能涵盖了以上各个方面的理论...

    基于HeapAnalyzer456.jar 分析java内存溢出

    4. **分析大对象**:HeapAnalyzer456.jar会展示对象的大小分布,找出占用内存最大的对象。这些大对象可能是内存溢出的原因,因为它们可能消耗了大量的内存空间。 5. **查找内存泄漏**:工具可以检测到哪些类或对象...

    提高Java开发质量之内存泄露

    内存泄露是指在程序运行过程中,对不再使用的对象或资源未能及时释放,导致这些对象继续占用内存空间的现象。在Java中,由于垃圾回收机制的存在,内存泄露的问题不如C/C++等语言中严重,但在某些情况下仍然会出现。 ...

    jbuilder中的内存查看工具

    5. **资源占用统计**:插件还能统计各个类或包所占用的内存,帮助定位内存消耗大户。 **使用步骤** 1. **安装插件**:将`jbmemmonitor.jar`添加到JBuilder的插件目录,并重启JBuilder以加载插件。 2. **启动监控**...

    Java内存管理问题案例分享_技术大学

    Java内存管理是Java编程中至关重要的一环,它关乎程序的性能、稳定性和资源效率。Java通过自动内存分配和回收机制,即垃圾收集(Garbage Collection, GC),减轻了程序员对内存管理的负担。然而,如果不深入理解Java...

Global site tag (gtag.js) - Google Analytics