`
javawebsoa
  • 浏览: 409849 次
社区版块
存档分类
最新评论

java内存分配机制

    博客分类:
  • java
阅读更多

       通过这几天对一个内存溢出程序的监控,学习了程序运行时对内存的使用机制,在这里和大家分享下。

        Java程序运行在JVM(Java  Virtual Machine,Java虚拟机)上,可以把JVM理解成Java程序和操作系统之间的桥梁,JVM实现了Java的平台无关性,由此可见JVM的重要性。所以在学习Java内存分配原理的时候一定要牢记这一切都是在JVM中进行的,JVM是内存分配原理的基础与前提。

        一个完整的Java程序运行过程会涉及以下内存区域:

 

        寄存器:JVM内部虚拟寄存器,存取速度非常快,程序不可控制。

        栈:保存局部变量的值,包括:a.用来保存基本数据类型的值;b.保存类的实例,即堆区对象的引用(指针)。也可以用来保存加载方法时的帧。

        堆:用来存放动态产生的数据,比如new出来的对象。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。

        常量池:JVM为每个已加载的类型维护一个常量池,常量池就是这个类型用到的常量的一个有序集合。包括直接常量(基本类型,String)和对其他类型、方法、字段的符号引用(1)。池中的数据和数组一样通过索引访问。由于常量池包含了一个类型所有的对其他类型、方法、字段的符号引用,所以常量池在Java的动态链接中起了核心作用。常量池存在于堆中

        代码段:用来存放从硬盘上读取的源程序代码。

        数据段:用来存放static定义的静态成员。

下图表示内存分配图:


 

对于java 和内存之间,有如下几点需要注意:

 1.一个Java文件,只要有main入口方法,我们就认为这是一个Java程序,可以单独编译运行。

  2.无论是普通类型的变量还是引用类型的变量(俗称实例),都可以作为局部变量,他们都可以出现在栈中。只不过普通类型的变量在栈中直接保存它所对应的值,而引用类型的变量保存的是一个指向堆区的指针,通过这个指针,就可以找到这个实例在堆区对应的对象。因此,普通类型变量只在栈区占用一块内存,而引用类型变量要在栈区和堆区各占一块内存。

3.分清什么是实例什么是对象。Class a= new Class();此时a叫实例,而不能说a是对象。实例在栈中,对象在堆中,操作实例实际上是通过实例的指针间接操作对象。多个实例可以指向同一个对象。

 4.栈中的数据和堆中的数据销毁并不是同步的。方法一旦结束,栈中的局部变量立即销毁,但是堆中对象不一定销毁。因为可能有其他变量也指向了这个对象,直到栈中没有变量指向堆中的对象时,它才销毁,而且还不是马上销毁,要等垃圾回收扫描时才可以被销毁。

 5.以上的栈、堆、代码段、数据段等等都是相对于应用程序而言的。每一个应用程序都对应唯一的一个JVM实例,每一个JVM实例都有自己的内存区域,互不影响。并且这些内存区域是所有线程共享的。这里提到的栈和堆都是整体上的概念,这些堆栈还可以细分。

6 .类的成员变量在不同对象中各不相同,都有自己的存储空间(成员变量在堆中的对象中)。而类的方法却是该类的所有对象共享的,只有一套,对象使用方法的时候方法才被压入栈,方法不使用则不占用内存。

55
12
分享到:
评论
27 楼 林晓盼 2012-06-14  
这是做基础介绍么?深入的都没讲吧。
26 楼 b87936260 2012-06-14  
说得很好,想问下所有jvm都是这样划分内存的吗?比如android的jvm
25 楼 dwbin 2012-06-14  
楼主是不是搞错了??感觉跟自己学的不太一样。
24 楼 王宏业 2012-06-14  
23 楼 tiantiangeq 2012-06-14  
  准备学习下 感谢楼主分享。望一帆风顺
22 楼 lucky16 2012-06-13  
以前学习java的时候看的thinking in java,里面都讲到了这个的,然后还有马士兵的java视屏也有,学java还是得把内存分配看看。。。
21 楼 java-xb 2012-06-13  
等于没讲什么
20 楼 hanazawakana 2012-06-13  
  准备学习下 感谢楼主分享。望一帆风顺
19 楼 vmgrind 2012-06-13  
runshine 写道
Harry9090 写道
一看到把常量池画到堆里面,我就不解了,迷惑!

//////////////////////*************
常量池 (constant pool)
常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用,比如:
◆类和接口的全限定名;
◆字段的名称和描述符;
◆方法和名称和描述符。
虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和 floating point常量)和对其他类型,字段和方法的符号引用。
对于String常量,它的值是在常量池中的。而JVM中的常量池在内存当中是以表的形式存在的, 对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引 用。说到这里,对常量池中的字符串值的存储位置应该有一个比较明了的理解了。
在程序执行的时候,常量池 会储存在Method Area,而不是堆中。
*************//////////////
转至http://zzc1684.iteye.com/blog/1457364

最后一句话,常量池,不在堆中!


不知道到底哪个是对的。


博主这篇文章很多概念太模糊了,你不能说它错,但似乎也不能说它对。
按着你的迷惑点,以及博主文章中提到的,应当先明确为运行时的常量池。
先按着JVM的规范来说,运行时数据区分为:程序计数器(Program Counter Register,也有翻译为PC寄存器),java虚拟机栈(Java Virtual Machine Stack),本地方法栈(Native Method Stack),Java堆,方法区(Method Area)。一共5个概念区域。并且规范中描述方法区是堆的逻辑组成部分。
jvm规范中明确说运行时常量池(Runtime Constant Pool)都分配在Java虚拟机的方法区。
但是——这个世界最怕但是——规范中没有强制规定方法区应该实现的内存区域,一如上一段中说方法区是堆的逻辑组成部分,但方法区有可能实现在java堆中的,也可能不在。
不过一般来说,无论方法区在哪,既然独立了方法区这么个概念,那么常量池就应该在方法区中,而不能说在堆中。

感觉博主是不是看过《thinking in java》然后被里面的乱七八糟的内存划分方法影响了?
常量池是jvm级别的,不是一个类一个,要把jvm里的常量池和class里的常量池描述部分区分开。
再有,“实例”一般指的就是“对象”。Class a= new Class(); 这里的a如果非要和对象区分的话,叫“引用”就可以了。
18 楼 iro 2012-06-13  
   通熟易懂
17 楼 javaeyehoney 2012-06-13  
16 楼 runshine 2012-06-13  
Harry9090 写道
一看到把常量池画到堆里面,我就不解了,迷惑!

//////////////////////*************
常量池 (constant pool)
常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用,比如:
◆类和接口的全限定名;
◆字段的名称和描述符;
◆方法和名称和描述符。
虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和 floating point常量)和对其他类型,字段和方法的符号引用。
对于String常量,它的值是在常量池中的。而JVM中的常量池在内存当中是以表的形式存在的, 对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引 用。说到这里,对常量池中的字符串值的存储位置应该有一个比较明了的理解了。
在程序执行的时候,常量池 会储存在Method Area,而不是堆中。
*************//////////////
转至http://zzc1684.iteye.com/blog/1457364

最后一句话,常量池,不在堆中!


不知道到底哪个是对的。


博主这篇文章很多概念太模糊了,你不能说它错,但似乎也不能说它对。
按着你的迷惑点,以及博主文章中提到的,应当先明确为运行时的常量池。
先按着JVM的规范来说,运行时数据区分为:程序计数器(Program Counter Register,也有翻译为PC寄存器),java虚拟机栈(Java Virtual Machine Stack),本地方法栈(Native Method Stack),Java堆,方法区(Method Area)。一共5个概念区域。并且规范中描述方法区是堆的逻辑组成部分。
jvm规范中明确说运行时常量池(Runtime Constant Pool)都分配在Java虚拟机的方法区。
但是——这个世界最怕但是——规范中没有强制规定方法区应该实现的内存区域,一如上一段中说方法区是堆的逻辑组成部分,但方法区有可能实现在java堆中的,也可能不在。
不过一般来说,无论方法区在哪,既然独立了方法区这么个概念,那么常量池就应该在方法区中,而不能说在堆中。
15 楼 onepiece135180 2012-06-13  
常量池在方法区
14 楼 inotgaoshou 2012-06-13  
13 楼 username2 2012-06-13  
复习中。。
12 楼 Harry9090 2012-06-13  
一看到把常量池画到堆里面,我就不解了,迷惑!

//////////////////////*************
常量池 (constant pool)
常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用,比如:
◆类和接口的全限定名;
◆字段的名称和描述符;
◆方法和名称和描述符。
虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和 floating point常量)和对其他类型,字段和方法的符号引用。
对于String常量,它的值是在常量池中的。而JVM中的常量池在内存当中是以表的形式存在的, 对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引 用。说到这里,对常量池中的字符串值的存储位置应该有一个比较明了的理解了。
在程序执行的时候,常量池 会储存在Method Area,而不是堆中。
*************//////////////
转至http://zzc1684.iteye.com/blog/1457364

最后一句话,常量池,不在堆中!


不知道到底哪个是对的。
11 楼 Se7enEleven 2012-06-13  
不错,浅显易懂,为深入理解JVM开了个好头
10 楼 zhuzl5210798 2012-06-13  
写的真好!顶!
有一点不清楚。楼主能详细点么?
常量池就是这个类型用到的常量的一个有序集合。包括直接常量(基本类型,String)和对其他类型、方法、字段的符号引用(1)
这段中的“和对其他类型、方法、字段的符号引用(1)” 不清楚。
9 楼 那家渔村 2012-06-13  
实例究竟是在堆中还是在java栈中?有点没搞明白。一直认为实例就是对象存在放Java堆中。而存放在java栈中我一般都认为是对象的引用。对于楼主的引用就是实例的说法表示不赞同!
8 楼 onepiece135180 2012-06-13  
去看看深入JAVA虚拟机,讲的更详细哦

相关推荐

    java内存分配机制详解

    文档中介绍了: 寄存器 栈 堆 静态域 常量池 帮助java学习者从本质上理解java的运行机制。

    java内存分配机制[归纳].pdf

    java内存分配机制[归纳].pdf

    JAVA虚拟机内存分配机制

    JAVA虚拟机内存分配机制 详细讲述了JAVA VM的内存分配 对深入理解JAVA有帮助

    Java 虚拟机学习笔记:Java 内存区域,垃圾收集,内存分配与回收策略,JVM 调优,文件结构,类加载机制,Java 程序

    内存分配与回收策略, JVM 调优, 文件结构, 类加载机制, Java 程序 Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的语言,意味着可以在不同的操作系统上运行。Java具有简单、...

    Java垃圾回收机制和内存分配

    你认真演示了一遍,你就能明白JAVA的垃圾回收机制。当然文档写的不一定全面,比如文档当中关于老年区少年区有一页写的不是很完整,我也没有添加太多进去,但是还是很有很全面很有参考意义的。

    java内存讲解

    内容包括:JVM的垃圾回收机制详解和调优;深入Java核心 Java内存分配原理精讲;详细介绍Java的内存管理与内存泄露,三个文档整合

    JAVA虚拟机内存分配与回收机制[文].pdf

    JAVA虚拟机内存分配与回收机制[文].pdf

    java主要反射和内存机制

    非常详细的讲解java的内存分配机制和java反射机制的文档,里面还有代码可以自己改写。

    java内存管理以及GC

    内存管理的职责为分配内存,回收内存。 没有自动内存管理的语言/平台容易发生错误。 典型的问题包括悬挂指针问题,一个指针引用了一个已经被回收的内存地址,导致程序的运行完全不可知。 另一个典型问题为内存...

    最详细的java内存讲解

    JVM的垃圾回收机制详解和调优; 深入Java核心 Java内存分配原理精讲; 详细介绍Java的内存管理与内存泄露;

    Java 内存分配深入理解

    主要介绍了Java 内存分配深入理解的相关资料,需要的朋友可以参考下

    Java的内存回收机制

    在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由JVM自动完成的,降低了Java程序员的学习难度,避免了像C/C++直接操作内存的危险。但是,也正因为内存管理完全由...

    Java内存回收机制

     内存泄露:程序运行过程中,会不断分配内存空间,那些不再使用的内存空间应该即时回收它们,从而保证系统可以再次使用这些内存,如果存在无用的内存没有被回收回来,这是内存泄漏.  (1)强引用  这是java程序...

    03-VIP-JVM内存分配机制与垃圾回收算法1

    1.1 对象优先在Eden区分配 1.2 大对象直接进入老年代 1.3 长期存活的对象将进入老年代

    java 垃圾回收 机制详解

    经过半个世纪的发展,内存的动态分配与内存回收技术已经相当成熟,一切看起来都进入了“自动化”时代,那为什么我们还要去了解GC和内存分配呢?答案很简单:当需要排查各种内存溢出、内存泄漏问题时,当垃圾收集成为...

    Java中变量内存分配机制

    在本文中,简单的为大家介绍有关,java中变量在内存是如何分配的。  在任何编程语言中,无论是基本类型还是引用类型,不论其作用域如何,都必须为其分配一定的内存空间,Java 语言也不例外,Java 的数据类型可以...

    java内存泄漏

     上面是Java内存管理机制的基本情况。但是如果仅仅理解到这里,我们在实际的项目开发中仍然会遇到内存泄漏的问题。也许有人表示怀疑,既然Java的垃圾回收机制能够自动的回收内存,怎么还会出现内存泄漏的情况呢?这...

    JVM内存分配与垃圾回收详解

    个人整理 jvm相关知识 包括内存分配机制 垃圾回收机制 垃圾收集器相关 及 垃圾收集算法

    JAVA 内存管理总结

     Java的内存管理是对象的分配和释放问题。(两部分)  分配 :内存的分配是由程序完成的,程序员需要通过关键字new 为每个对象申请内存空间 (基本类型除外),所有的对象都在堆 (Heap)中分配空间。  释放 :...

    Java GC 机制与内存分配策略详解

    主要介绍了Java GC 机制与内存分配策略详解的相关资料,需要的朋友可以参考下

Global site tag (gtag.js) - Google Analytics