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

Java内存分析(转载)

阅读更多
JAVA中,有六个不同的地方可以存储数据:
1. 寄存器(register)。这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部。但是寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配。你不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象。
2. 堆栈(stack)。位于通用RAM中,但通过它的“堆栈指针”可以从处理器哪里获得支持。堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些内存。这是一种快速有效的分配存储方法,仅次于寄存器。创建程序时候,JAVA编译器必须知道存储在堆栈内所有数据的确切大小和生命周期,因为它必须生成相应的代码,以便上下移动堆栈指针。这一约束限制了程序的灵活性,所以虽然某些JAVA数据存储在堆栈中——特别是对象引用,但是JAVA对象不存储其中。
3. 堆(heap)。一种通用性的内存池(也存在于RAM中),用于存放所以的JAVA对象。堆不同于堆栈的好处是:编译器不需要知道要从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当你需要创建一个对象的时候,只需要new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用堆进行存储分配比用堆栈进行存储存储需要更多的时间。
4. 静态存储(static storage)。这里的“静态”是指“在固定的位置”。静态存储里存放程序运行时一直存在的数据。你可用关键字static来标识一个对象的特定元素是静态的,但JAVA对象本身从来不会存放在静态存储空间里。
5. 常量存储(constant storage)。常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变。有时,在嵌入式系统中,常量本身会和其他部分分割离开,所以在这种情况下,可以选择将其放在ROM
6. RAM存储。如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在。
 
上面这段话摘取之《Thinking in Java》』
 
---------------------------------------------------------------------
堆是一个运行时数据区,类的对象从中分配空间。这些对象通过new建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。java中的对象和数组都存放在堆中。
栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象引用。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:
int a = 3;
int b = 3
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了ab同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。
 
以上内容也是摘抄自网上。
 
---------------------------------------------------------------------
下面我自己来举几个例子:
 [code="java"]
public class TestStr {
  public static void main(String[] args) {
    // 以下两条语句创建了1个对象。"凤山"存储在字符串常量池中
    String str1 = "凤山";
    String str2 = "凤山";
    System.out.println(str1==str2);//true
    
    //以下两条语句创建了3个对象。"天峨",存储在字符串常量池中,两个new String()对象存储在堆内存中
    String str3 = new String("天峨");
    String str4 = new String("天峨");
    System.out.println(str3==str4);//false
    
    //以下两条语句创建了1个对象。9是存储在栈内存中
    int i = 9;
    int j = 9;
    System.out.println(i==j);//true
    
      //以下两条语句创建了1个对象。1对象存储在栈内存中
    Integer l = 1;//装箱
    Integer k = 1;//装箱
    System.out.println(l==k);//true
    
    //由于没有了装箱,以下两条语句创建了2个对象。两个1对象存储在堆内存中
    Integer l1 = new Integer(1);
    Integer k1 = new Integer(1);
    System.out.println(l1==k1);//false
    
    //以下两条语句创建了1个对象。i1,i2变量存储在栈内存中,两个256对象存储在堆内存中
         Integer i1 = 256;
                Integer i2 = 256;
         System.out.println(i1==i2);//false
  }
}
[/code]
对于以上最后两个关于Integer对象的例子,在自动装箱时对于值从–128127之间的值,使用一个实例。
下面是对字符串常量池()的一个例子:
String s1 = "aaa" + "bbb"; //产生了1个对象。
由于常量的值在编译的时候就被确定了。在这里,"aaa""bbb"都是常量,因此变量s1 的值在编译时就可以确定。这行代码编译后的效果等同于:
String s1 ="aaabbb";
因此这里只创建了一个对象"aaabbb",并且它被保存在字符串池里了。
 
String str1 = "凤山";
String str2 = "凤山";
以上两条语句只在常量池中保存了一个"凤山"对象。
 
String str3 = new String("天峨");
String str4 = new String("天峨");
以上两条语句创建了3个对象,首先在字符串常量池中创建一个"天峨"对象,接着在堆内存中创建两个new String()对象,里面保存的是指向"天峨"对象的引用。
另:“==在判断对象时,其实是根据对象在堆栈中的地址判断对象是不是一样,而不是根据hashcode 值。
 
 
在网上看见这段对Java String中的HashCodeequal的总结比较好,记录如下:
    1. hashSet中比较是否重复的依据是a.hasCode()=b.hasCode() && a.equalsb
    2. StringhashCode依据: 以依赖于char[i]int值以和char[i]的排列序的算法计算出的(可以去看看源码)。不依赖Stringref.
    3. Stringequals依据: a==b || a.length=b.length && { a[i]=b[i] }
    4. 只有用a==b时比校的才是比校的ref,也就是说这时才是比校是ab是不是同一个对象
    5. 结论: 两个不同refString可能会被认为是集合中的同一个元素。
 
---------------------------------------------------------------------
下面分析一个代码示例:
class BirthDate {
        private int day;
        private int month;
        private int year;        
        public BirthDate(int d, int m, int y) {
                day = d;    
                month = m;    
                year = y;
        }
        省略get,set方法。。。
        public void display() {
        System.out.println
                (day + " - " + month + " - " + year);
        }
}
    
public class Test{
        public static void main(String args[]){
                Test test = new Test();
                int date = 9;
                BirthDate d1= new BirthDate(7,7,1970);
                BirthDate d2= new BirthDate(1,1,2000);        
                test.change1(date);
                test.change2(d1);
                test.change3(d2);
                d1.display();
                d2.display();
        }
        
        public void change1(int i){
        i = 1234;
        }
        
        public void change2(BirthDate b) {
        b = new BirthDate(22,2,2004);
        }
        
        public void change3(BirthDate b) {
        b.setDay(22);
        }
}
以下为对内存的分析:
 
 
成员变量:方法外部,类的内部定义的变量。
局部变量:方法或语句块内部定义的变量。
 
再贴上一张程序执行过程的图片(截取自尚学堂):
 

本文出自 “青山” 博客,请务必保留此出处http://java999.blog.51cto.com/259217/134359

  • 大小: 55.9 KB
  • 大小: 63.9 KB
分享到:
评论

相关推荐

    深入分析 Java I/O 的工作机制(转载)

    以下是对Java I/O机制的详细分析: 1. **I/O 流的概念** Java中的I/O操作基于流的概念,流是数据的有序传输通道。Java将所有的I/O操作抽象为流对象,分为字节流和字符流两大类。字节流处理单个字节的数据,如...

    java多线程扫描器(转载)

    此项目的核心目标在于分析系统的可行性,明确开发方向,确保开发过程的合理性。它要求开发者能够精确识别系统流程,熟练运用Java编程技术,通过互联网资源及专业书籍搜集相关信息,最终完成一个基于Java的应用系统...

    Java 9 High Performance

    5. Java性能基准测试:书中可能会讨论如何衡量和分析Java应用程序的性能,包括使用不同的基准测试工具和方法。 版权信息显示,这本书的版权归Packt Publishing所有,其在未获得出版商明确许可的情况下,不得复制或...

    转载的供大家分享

    此外,使用内存分析工具(如VisualVM或JProfiler)可以帮助识别内存泄漏的具体对象和引用链。 除此之外,其他常见的性能问题包括线程池的优化、数据库连接池管理、缓存策略的设定、代码级别的效率问题(如过度的...

    Java面试资料大集合

    通过阅读《Java常见面试题.doc》、《Java面试题1.htm》、《5559.htm》、《Java面试题2.htm》、《java面试笔试题大汇总 及c-c++面试试题(转载 ) - happyfish - BlogJava.mht》以及《Java常见面试题.txt》等文件,您...

    [转载]hotspot源码(JDK7)

    Hotspot实现了Java内存模型(JMM),确保了多线程环境下的数据一致性。它定义了变量访问规则、线程交互规则以及内存可见性,确保了并发编程的正确性。 5. **类加载机制** Hotspot遵循双亲委托模型进行类加载,从...

    MemoryAnalyzer-1.10.0.20200225-win32.win32.x86-64.zip

    内存溢出分析工具、举例分析dump下的hprof文件 Shallow Heap :一个对象所占用的内存,不包含对其他对象的引用 Retained Heap :是shallow Heap的总和(单个对象占用内存*此对象的个数),也就是该对象被GC之后所能...

    JNA—JNI终结者(转载)

    4. **内存管理**:JNA负责内存管理,避免了JNI中的内存泄漏问题。 **JNI详解** 相比之下,JNI是Java平台标准的一部分,提供了与本地代码交互的底层接口。虽然它提供了更灵活的控制,但学习曲线较陡峭,因为开发者...

    jdk常用命令

    7. **jvisualvm**:集成在JDK中的多合一Java应用性能分析工具,提供丰富的可视化数据,包括CPU、内存、线程等。 8. **jmap**:用于生成堆转储文件(heap dump),帮助分析内存泄漏。例如,`jmap -dump:format=b,...

    使用open source产品组装你的web应用架构(转载)

    Nginx以其高性能和低内存占用而著名,适合处理高并发场景;而Apache则以其灵活性和广泛的模块支持受到青睐。 2. **应用服务器**:对于动态内容处理,应用服务器如Tomcat(Java)或Passenger(Ruby on Rails)是核心...

    spark使用案例------

    Spark是Apache Hadoop生态系统中的一个快速、通用且可扩展的大数据处理框架,它以其高效的内存计算和DAG(有向无环图)执行模型而闻名。Spark提供了多种API,包括Scala、Java、Python和R,使得开发人员可以方便地...

    C#合并word文档类

    另一种更现代、更高效的方法是使用第三方库,如Spire.Doc或Apache POI(针对.NET的Java库的移植)。 "DocMerger.cs"文件很可能是一个自定义的C#类,用于实现Word文档的合并功能。这个类可能包含以下关键组件: 1. ...

    二十三种设计模式【PDF版】

    很简单一个模式,就是在内存中保留原来数据的拷贝. 设计模式之 Interpreter(解释器) 主要用来对语言的分析,应用机会不多. 设计模式之 Visitor(访问者) 访问者在进行访问时,完成一系列实质性操作,而且还可以扩展. ...

    SweetScape 010 Editor 8 汉化版

    十六进制编辑器是一种允许您查看和编辑二进制文件中个别 字节的程序,而高级的十六进制编辑器(包括 010 Editor)还允许您编辑硬盘驱动器、软盘驱动器、内存密钥、闪存驱动器、光驱和进程中的字节。 SweetScape 010 ...

Global site tag (gtag.js) - Google Analytics