`
iihero
  • 浏览: 257764 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

关于Java占用内存的研究

阅读更多
这篇文章来自newsmthBBS java版原版主zms的经验总结,感觉挺不错。转到这里,以供参考。

最近对程序占用内存方面做了一些优化,取得了不错的效果,总结了一些经验
简要说一下,相信会对大家写出优质的程序有所帮助
下面的论述针对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<String,Integer>的结构,有100万个元素
改为String[]+int[]后,内存占用改观不少,速度也很快
100万的String[] 快排一下,也就2秒多,查找用2分,和hash也差不多少

完!


说明:
1。 以上结论适用于32位系统,对于64位系统,有很多不同。反正结论是虽然64位系统能用的内容更多了,但相同的程序占用内存也多了不少
2。 上面讨论的是类的实例占用的内存,没有考虑静态变量的占用。 静态变量引用的是算在Class数据里的,内容的占用和实例无关,单独计算就可以了
3。 以上没有考虑 Class本身占的内存。 Class本身也需要占地方啊,就是类的结构,以及静态变量的引用的占用。但是这个占用是静态的,不随实例变多而变多的。也不好统计出来,想统计的话,看jvm源码里jclass的表示
4。 别人的劳动成果请尊敬,转载请注明作者zms。
分享到:
评论

相关推荐

    Java占用内存的研究.pdf

    在本文档中,我们主要研究了Java中对象和数据结构的内存占用情况。Java语言因为其跨平台特性,在内存使用上有一套自己的规则。特别地,Java虚拟机(JVM)管理内存的方式使得开发者需要了解一些基本的内存占用知识,...

    Java虚拟内存研究

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

    JAVA虚拟机内存使用优化研究与应用.pdf

    根据提供的文件内容,以下是关于JAVA虚拟机(JVM)内存使用优化的知识点: 1. JVM内存优化的重要性:在运行Java应用程序时,尤其是涉及到大量数据查询和高并发操作的场合,系统可能由于内存溢出而不稳定。JVM内存...

    java内存对象分配过程研究

    ### Java内存对象分配过程研究 #### 一、引言 Java作为一门强大的面向对象编程语言,在实际开发过程中,对象的创建及其内存管理是至关重要的环节。深入理解对象在内存中的分配过程不仅能够帮助开发者设计出更为...

    Java程序内存行为研究.pdf

    总之,Java程序内存行为的研究对于提升程序性能、优化垃圾收集策略以及实现能源效率具有深远影响。通过掌握内存分配模式、对象生命周期、内存使用轨迹等规律,开发者可以更好地调整代码,以达到性能和能耗的最佳平衡...

    java内存泄漏问题追踪

    - 本地方法栈内存泄漏:Java Native Interface (JNI) 使用的本地方法可能会占用C/C++堆内存,如未释放,可能导致内存泄漏。 2. 内存泄漏的检测: - Java VisualVM:这是JDK自带的工具,可以进行内存快照分析,...

    Java程序内存泄漏研究.pdf

    1. 静态集合类中的引用:静态字段不会被GC回收,如果这些字段引用了大量对象,即使这些对象不再使用,也会持续占用内存。 2. 未关闭的资源:如数据库连接、文件流或其他IO流,如果没有正确关闭,可能导致内存泄漏,...

    Java系统中内存泄漏测试方法的研究

    这篇研究主要探讨了如何检测和分析Java应用中的内存泄漏问题。以下是对这个主题的详细阐述: 一、内存泄漏的理解 内存泄漏是指程序在申请内存后,无法释放已经不再使用的内存空间,一次小的内存泄漏可能不明显,但...

    JAVA虚拟机的内存管理

    此外,还将提供一些影响内存收集器行为的常见选项,并附有详细的文档链接以供进一步研究。 #### 二、手动与自动内存管理 ##### 手动内存管理的问题 - **悬挂引用**:当一个对象被其他对象引用,但其内存已被释放...

    java 虚拟机 内存和栈 分析工具 ha456.rar

    通过这些工具,我们可以查看对象的分布情况,找出占用内存大的对象,分析其生存周期,判断是否应被垃圾回收。同时,检查栈中的对象状态,理解方法调用过程中的资源消耗。 了解并掌握这些内存和栈的分析技巧,对优化...

    用JAVA做的虚拟内存管理.rar,JDK是6.2

    总的来说,这个项目为初学者提供了一个了解Java虚拟机内存管理的实践平台,通过研究源代码,可以深入理解JVM如何在JDK 6.2版本中管理内存,以及如何使用和配置这些内存区域,这对于提升Java开发技能非常有帮助。...

    java中带有不同构造方法的程序内存分析

    垃圾回收器会定期检查不再被引用的对象,并释放它们占用的内存,以便重新利用。构造方法在创建对象时起到了初始化的作用,但并不直接影响垃圾回收。不过,如果构造方法创建了大量的临时对象或者资源,开发者需要确保...

    JAVA的内存结构Java系列2021.pdf

    程序计数器是占用内存空间最小的区域之一,它的主要作用是记录线程所执行的字节码指令的地址,以确保线程切换后能够恢复到正确的执行位置。它是线程私有的,因此,不同线程之间的程序计数器互不影响。在JVM规范中,...

    网络编程语言Java的内存泄露原因分析及处理措施

    本文重点分析研究了 Java 内存泄露的原因及表现形式,并在此基础上提出了内存泄露的处理措施。 Java 内存泄露的原因可以分为两类:客观原因和主观原因。客观原因主要是垃圾收集器的回收机制的作用,垃圾收集器对...

    Java系统中内存泄漏测试方法的研究.doc

    在这种情况下,即使对象的实际功能已经结束,它依然占用着内存,随着时间推移,这些未释放的内存会积累,最终可能导致系统运行缓慢甚至崩溃。 解决内存泄漏通常有两种思路:一是通过代码审查,由有经验的开发人员...

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

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

    Java(JVM)虚拟机结构基础(转自Java研究组织)

    其中,垃圾回收(GC)是自动管理堆内存的关键机制,旨在释放不再使用的对象所占用的内存空间,提高程序的运行效率和稳定性。 #### 指令集与字节码 JVM支持一系列的字节码指令,如iadd(整型加法)、ladd(长整型加法...

Global site tag (gtag.js) - Google Analytics