`

java 内存区域划分

    博客分类:
  • java
 
阅读更多

堆(Heap)和非堆(Non-heap)内存
按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。 
堆内存分配
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。 
非堆内存分配
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。 
JVM内存限制(最大值)
首先JVM内存限制于实际的最大物理内存(废话!呵呵),假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。

 

我们常常做的是将Java内存区域简单的划分为两种:堆内存和栈内存。这种划分比较粗粒度,这种划分是着眼于我们最关注的、与对象内存分配密切相关的两类内存域。其中栈内存指的是虚拟机栈,堆内存指的是java堆。

1.栈内存,即虚拟机栈。每个方法被执行的时候都会同时创建一个栈帧,用来存储局部变量,操作栈,动态链接,方法出口等信息。局部变量包括各种基本类型的变量和对象的引用变量都是在方法的栈内存中分配。其中,64位长度的long和double类型的数据占用2个局部变量的空间,其他数据类型只占用1个。局部变量所需要的内存空间是在编译期间完成的,当进入一个方法时候,这个方法所需的局部变量空间已经确定,在方法运行期间不会改变。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。当线程请求的栈深度大于虚拟机所允许的深度,则抛出StackOverflowError异常。当虚拟机栈无法扩展时候则抛出OutOfMemoryError异常。出现这种情况的解决办法具体参见java调优。
2.堆内存,在虚拟机启动时创建。堆内存的唯一目的就是创建对象实例,所有的对象实例和数组都要在堆上分配。堆是由垃圾回收来负责的,因此也叫做“GC堆”,垃圾回收采用分代算法,堆由此分为新生代和老年代。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。当堆内存因为满了无法扩展时就会抛出java.lang.OutOfMemoryError:Java heap space异常。出现这种情况的解决办法具体参见java调优。
   其实,Java内存不只局限于以上两种,还有:

1
   1.程序计数器,(上图中的线程pc寄存器)记录当前线程所执行的字节码的行号。
   2.本地方法栈,与上面的虚拟机栈类似,只不过虚拟机栈是为java方法服务,而本地方法栈是用来为native方法服务。
   3.方法区,用于存放已被虚拟机加载的类信息、常量、静态变量。垃圾回收在这个区域出现的几率少。在这个区域的回收就是类型的卸载。只有当加载该类型的类加载器实例(非类加载器类型)为unreachable状态时,当前被加载的类型才被卸载。所以一般不会被卸载。
   4.运行时常量池,存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放在方法区的运行时常量池中。该区域不会被回收,例如
Strings="abc";
s="xyz";
s=null;
"abc"和"xyz"将一直存在于在字符串池中,这就是java内存泄露的原因之一。

由于Reference类型在Java虚拟机规范里面只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位,以及访问到Java堆中的对象的具体位置,因此不同虚拟机实现的对象访问方式会有所不同,主流的访问方式有两种:使用句柄和直接指针:

如果使用句柄访问方式,Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息如下图所示:

通过句柄方式访问对象

 

如果使用直接指针访问方式,java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,reference中直接存储的就是对象地址。如下图所示:

通过直接指针方式访问对象

 

 

这两种对象的访问方式各有优势,使用句柄访问方式的最大好处就是reference中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而reference本身不需要被修改。

使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的的时间开销。

分享到:
评论

相关推荐

    浅谈Java内存区域划分和内存分配策略

    "浅谈Java内存区域划分和内存分配策略" 本文将详细讲述Java内存区域划分和内存分配策略,涵盖程序计数器、虚拟机栈、本地方法栈、堆、方法区等内存区域的概念和作用,以及对象创建过程和内存分配策略。 程序计数器...

    Java的内存管理机制分析

    #### 一、Java内存区域划分 Java的内存管理机制将内存分为以下几个区域: 1. **栈(Stack)**: - 存储局部变量(如基本类型的变量和对象的引用)。 - 每个线程拥有一个独立的栈。 - 栈内存中的数据在方法执行...

    java内存分配详解

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

    Java 内存区域和GC机制

    Java内存区域和垃圾收集(GC)机制是Java编程中至关重要的一部分,它关乎程序的性能、稳定性和资源管理。本文将深入探讨Java虚拟机(JVM)中的内存划分、垃圾收集的工作原理以及相关工具的使用。 1. **Java内存区域...

    JVM内存区域划分Java系列2021.pdf

    JVM内存区域划分详细解析: JVM(Java Virtual Machine,Java虚拟机)是运行Java字节码的虚拟机进程。在JVM中,内存区域被划分为几个不同的部分,每一个部分有着不同的用途,从而实现了JVM的稳定和高效运行。根据...

    JVM内存区域划分.docx

    JVM内存区域划分是Java虚拟机(JVM)中的一种内存管理机制,主要分为五个部分:程序计数器、Java栈、本地方法栈、堆和方法区。这些区域各自扮演着不同的角色,共同组成了JVM的内存管理系统。 程序计数器 程序...

    java内存管理 ppt

    下面将深入探讨这些内存区域以及相关的垃圾收集和并发收集机制。 1. **堆内存**:Java对象主要存储在堆内存中,它是所有线程共享的一块区域。堆内存由Java虚拟机(JVM)自动管理,通过新生代、老年代和永久代来划分...

    java内存模型文档

    1. **内存区域划分** - **程序计数器**:每个线程都有自己的程序计数器,记录当前线程执行的字节码指令地址。 - **虚拟机栈**:存储方法的局部变量、操作数栈、动态链接等信息,每个方法调用对应一个栈帧。 - **...

    JVM 性能调优_JVM 内存区域划分.pdf

    JVM性能调优_JVM内存区域划分 JVM(Java Virtual Machine)是 Java 语言的核心组件之一,其性能优化对 Java 应用程序的执行效率和稳定性具有至关重要的影响。在 JVM 中,内存区域的划分和管理是性能优化的关键所在...

    在实例化对象的过程中需要在内存中开辟空间,这其中就包括栈内存和对内存。

    #### 一、Java内存区域划分 Java程序在运行过程中涉及多种不同的内存区域,其中最重要的是栈内存和堆内存。这两种内存分别用于存储不同类型的数据,并且具有不同的生命周期。 #### 二、栈内存与堆内存 1. **栈...

    java里的堆和栈

    #### 二、Java内存区域划分 在Java中,内存主要划分为以下几部分: 1. **栈区**:主要用于存储局部变量、函数调用过程中的临时数据等。它是按先进后出的原则操作的。 2. **堆区**:用于动态分配内存空间,存储所有...

    JVM内存区域划分.pdf

    在Java的学习过程中,我们不可避免地需要了解JVM(Java虚拟机)的工作原理,尤其是内存区域的划分。JVM的内存区域主要分为以下几个部分:程序计数器、Java虚拟机栈、本地方法栈、堆以及方法区。这些部分共同协作,...

    Java garbage minibook

    ##### Java 内存区域划分 Java 应用程序的内存被划分为几个主要部分: 1. **方法区**:用于存储类的信息、静态变量、常量池等内容。 2. **堆**:所有对象实例都在这里分配内存。堆是垃圾回收的主要关注点。 3. **栈*...

    Java基础知识总结大全

    #### 一、Java内存区域划分 Java程序运行时,根据不同的功能需求,被划分为几个不同的内存区域,主要包括: 1. **寄存器**:寄存器是CPU的一部分,用于存放计算过程中的临时数据,通常与处理器紧密相关,访问速度...

    JAVA 内存设置原理

    ### JAVA内存设置原理详解 在深入探讨JAVA内存设置原理之前,我们先理解一下JVM(Java虚拟机)的内存管理机制。JVM是JAVA运行时环境的核心,它负责执行JAVA字节码,同时管理程序运行时的内存分配与回收。JVM的内存...

    java秋招笔试面试知识点总结

    1. Java内存区域划分:Java虚拟机在执行Java程序时,会将内存分为几个不同的数据区域。其中包括寄存器、本地方法栈、方法区、堆、栈。寄存器用于存储指令,本地方法栈用于支持JVM调用本地方法,方法区存放加载的类...

    Java内存分配浅析

    了解这些内存区域后,我们可以通过实例来进一步理解Java程序的运行过程。例如,当创建一个类的实例时,JVM会在堆中分配空间,然后在栈中存储一个指向该对象的引用。对于基本类型的变量,它们的值直接存储在栈中;而...

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

    Java中的内存管理主要涉及到堆内存(Heap)和栈内存(Stack),这两者在程序执行时承担着不同...此外,理解Java内存模型对于解决并发问题也至关重要,因为多线程环境下,堆内存的共享特性可能导致数据竞争和同步问题。

    java实现内存动态分配

    这些区域在Java内存模型中同样占有重要地位,但在“java实现内存动态分配”的上下文中,主要关注堆和栈的动态分配。 综上所述,Java实现内存动态分配涉及到对堆内存、栈内存的理解,以及对垃圾回收机制的掌握。通过...

Global site tag (gtag.js) - Google Analytics