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

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内存分配机制中的几个关键概念:寄存器、栈、堆、静态域、常量...

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

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

    java内存分配情况

    Java内存分配主要涉及五个区域:寄存器、栈、堆、静态域和常量池。在Java编程中,理解这些内存区域的分配规则对于优化代码性能和避免内存泄漏至关重要。 1. **寄存器**:这是最快捷的存储区域,但不在Java程序员的...

    深入Java核心 Java内存分配原理精讲

    Java内存分配机制是Java编程语言的重要组成部分,它不仅直接影响着程序的性能,也是理解Java垃圾回收、内存泄漏等问题的关键。本文将聚焦于Java内存分配的核心概念,包括栈、堆、常量池等关键区域的功能与使用场景,...

    Java内存分配浅析

    Java内存分配是Java编程中非常重要的概念,它涉及到程序运行时的数据存储和管理。Java程序在JVM(Java Virtual Machine,Java虚拟机)上运行,JVM作为一个平台无关的执行环境,负责Java程序的内存管理和执行。理解...

    Java内存分配原理精讲

    ### Java内存分配原理精讲 #### 一、引言 Java作为一门广泛应用于企业级开发的语言,其内存管理和分配机制是其核心技术之一。本文旨在深入探讨Java内存分配的基本原理及其在不同内存区域的具体表现,帮助读者更好...

    java实现内存动态分配

    Java 实现内存动态分配主要涉及Java内存模型以及内存管理机制,包括堆内存和栈内存的分配,以及垃圾回收等概念。下面将详细解释这些知识点。 1. **Java内存模型** Java程序运行时,内存分为堆内存(Heap)和栈内存...

    java内存分配演示程序

    "java内存分配演示程序"是一个用于理解Java内存模型和内存分配过程的项目。在这个课程设计中,你将深入学习Java如何在运行时为对象分配内存,以及垃圾收集器如何回收不再使用的内存。以下是关于Java内存分配的一些...

    深入Java核心_Java内存分配原理精讲

    总结,深入理解Java内存分配原理意味着深入理解Java运行机制,这将帮助开发者编写出更高效、更健壮的代码,提升系统的整体性能和稳定性。通过学习和实践,开发者可以更好地应对内存溢出、性能瓶颈等问题,从而成为...

    java内存对象分配过程研究

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

    java核心 内存分配问题

    Java 内存分配是理解Java程序性能和...理解Java内存分配对于编写高效、无内存泄漏的代码至关重要,同时也对诊断和解决性能问题有着深远的影响。通过深入了解这些概念,开发者能够更好地设计和优化他们的Java应用程序。

    java内存分配 内存泄漏

    理解Java内存分配和JVM工作原理对于开发高效、健壮的Java应用至关重要。开发者应避免内存泄漏,合理使用内存,充分利用JVM的垃圾收集机制,同时理解JIT编译的优化策略,以提高程序的运行性能。在开发过程中,使用...

    Java内存分配全面解析

    Java内存分配全面解析 Java程序在执行过程中,其内存分配主要涉及到JVM(Java Virtual Machine,Java虚拟机)的不同区域。这些区域包括寄存器、栈、堆、常量池、代码段和数据段。理解这些内存区域的工作原理对于...

    java实现的内存分配

    Java内存分配的核心机制是垃圾收集(Garbage Collection, GC),它负责自动回收不再使用的内存。Java提供了几种不同的垃圾收集器,如Serial、Parallel、Concurrent Mark Sweep (CMS) 和G1等,它们各有优缺点,适用于...

    java内存机制及异常处理

    Java内存机制是Java虚拟机(JVM)的关键组成部分,它管理着程序运行时的数据存储。在Java中,内存主要分为以下几个区域: 1. **Heap(堆)**:这是Java中最主要的内存区域,用于存储所有的类实例和数组。当堆空间...

    Java中堆内存与栈内存分配浅析

    本文将深入探讨Java中堆内存与栈内存的分配机制,并通过对比分析它们之间的差异,帮助读者更好地掌握Java内存管理的核心概念。 #### 二、堆内存与栈内存概述 ##### 1. 堆内存 堆内存是Java虚拟机(JVM)用于存储...

    java内存分配详解

    ### Java内存分配详解 #### 一、Java内存区域划分 Java程序在运行过程中涉及的内存主要分为两大类:栈内存和堆内存。 1. **栈内存**:主要用于存储局部变量,如基本数据类型变量(int、long、char等)以及对象的...

    java 内存分配 适应法

    本篇文章将深入探讨Java内存分配中的“最先适应法”、“最佳适应法”和“最坏适应法”,这些都是内存管理中的经典算法,适用于不同的场景和需求。 首先,我们来看“最先适应法”(First Fit)。这是一种简单的内存...

    Java的内存管理机制分析

    通过对Java内存管理机制的深入分析,我们可以了解到Java如何高效地管理和利用内存资源。理解这些机制对于优化Java应用程序的性能至关重要,特别是在处理大规模数据集或多线程环境时。此外,合理配置JVM参数和选择...

Global site tag (gtag.js) - Google Analytics