Java程序在运行时需要在内存中分配空间。为了提高计算效率,Java虚拟机将在执行Java程序的过程中将其管理的内存分为几个不同的内存区域,因为每个区域都有特定的处理数据和内存管理方法。
@[TOC]
根据“ Java Virtual Machine规范(Java SE 7版)”,Java虚拟机管理的内存将主要包括以下运行时数据区域:程序计数器,方法区域,堆,虚拟机堆栈,本地方法stackthere是其他一些特殊的内存区域,例如恒定池,直接内存(而不是JVM内存)等。
程序计数器寄存器是一个较小的内存空间。它可以是当前线程执行的字节代码的行号指示器,也称为PC寄存器(PC寄存器)。启动每个线程时,创建了一个程序计数器。
在虚拟机的概念模型(仅概念模型,可以以更有效的方式实现各种虚拟机),字节码解释器通过更改计数器的值来选择需要执行的下一个需要执行的字节码来实现。基本功能,例如分支,循环,跳跃,异常处理和线程恢复都需要依靠此计数器才能完成。
由于多线程Java虚拟机是通过线程和分配处理器(CPU)执行时间来实现的,因此在任何某个时间内,处理器(CPU,用于多核处理器是kernel是一个内核))将执行线程中的所有说明)(通常在使用时间胶片旋转方法中使用CPU来占用线程旋转,因此在使用当前线程CPU时间平板电脑后,应进行CPU。)因此,为了在之后返回正确的执行位置切换线程,每个线程都需要具有独立的程序计数器。各个线程之间的计数器不会相互影响并独立存储。
在JVM规范中规定,如果线程执行非本地方法,即Java方法,则需要在程序计数器中执行的指令的地址;如果线程执行本机方法,则程序计数器中的值是未定义的。该内存区域是JVM规范未指定任何OutofMemoryError的唯一区域。
Java虚拟机堆栈(Java Virtual Machine堆栈)也是私有的,其生命周期与线程相同。虚拟机堆栈描述了由Java方法执行的内存模型:存储一个堆栈框架,每个堆栈框架对应于一个执行时,方法称为方法,每种方法都形成一个堆栈框架。堆栈框架包括本地变量表,操作堆栈,对Runstant池的引用和方法返回地址(引用运行时常数池)到当前方法。有些其他信息。
本地变量表存储了多种基本数据类型(布尔,字节,char,short,int,float,long,double)和对象参考参考指针的起始地址的参考指针也可能是指代表对象或其他对象的句柄与此对象相关的位置)和returnAddress类型(字节代码指令的地址)。
其中,64位长度和双重类型数据将占据2个本地变量空间(插槽),其余数据类型只会占用1个。在编译期间分配了本地变量表所需的存储空间。输入方法时,此方法需要由需要在框架中分配的局部变量空间完全确定。在方法操作过程中,将不会更改局部变量表的大小。
在Java虚拟机规范中,该区域规定了两个异常条件:如果线程要求的堆栈深度大于虚拟机允许的深度,则将抛弃stackoverflowerror异常;虚拟机可以动态地进行动态扩展,但是Java虚拟机规范也被允许为固定的长度虚拟机堆栈。如果您在扩展时无法申请足够的内存,则将抛出OutofMemoryError异常。
Java虚拟机实现可以使用传统堆栈(通常是CSTACK)来支持本机方法的执行(参考使用Java以外的其他语言编写方法)。此堆栈是本地方法堆栈。
虚拟机堆栈执行虚拟机的Java方法(字节代码)服务,而本地方法堆栈为虚拟机使用的本机方法服务。SUN热点直接结合了本地方法堆栈和虚拟机堆栈。本地方法堆栈还抛出了Stackoverflowerror和OutofMemoryError。
Java Heap(Java Heap)是JVM内存管理的最大区域。该内存区域的唯一目的是存储对象的示例。所有对象实例和数组都必须在堆上分配内存。几乎所有对象实例都在这里分配以分配此处。Memory,但是随着JIT编译器的开发和逃生分析技术的开发逐渐成熟,堆栈分配和数量替换优化技术将导致一些微妙的变化。“绝对”,这些,这些,这些,这些,这些都会导致这些变化。稍后将提及两种技术。
它也是垃圾收集器的主要管理区域,因此通常称为“ GC Heap”。堆内存可以根据GC分为几个部分。它将在“堆内存”模型和垃圾回收部分中提及。
从内存回收的角度来看,由于收集器基本上是由一代集合算法使用的,因此Java堆也可以细分为:新一代和老年;空间,等等。
从内存分配的角度来看,线程签名的Java桩可能会划分多个线程私有分配的缓冲区(TLAB)。无论如何,无论划分如何划分,它都与存储的内容无关。无论哪个区域,存储仍然是对象实例。
根据Java虚拟机的规定,只要在逻辑上是连续的,Java堆就可以在物理不连续的空间中。根据可扩展(通过-XMX和-XMS控件)实现。如果堆中没有内存完成实例分配,并且无法扩展堆,则将抛出OutofMemoryError。
通过使用JIT即时编译器的应用,您可以对代码进行逃生分析。逃生分析是一种分析技术,该技术确定对象是由外部方法引用还是由外部线程访问。优化的措施,编译器将根据逃生分析的结果来优化代码。
Java的逃生分析是一种方法级别,因为JIT的即时编译是方法级别。
通过逃生分析,可以进一步优化:
该方法区域也是JVM中非常重要的区域。它是由堆等线程共享的区域。,运行常数池(逻辑包含字符串常数池),等等。
方法区域是桩的逻辑部分。为了区分Java堆,它也有一个非异理。依赖于说话,GC很少出现在该区域的收集中。当方法区域无法满足内存分布的需求时,将抛弃OutofMemoryError。
在Java7和以前的版本中,我们还习惯说该方法区域是“永久一代”。更确切地说,应该是“热点已经实现了永久方法区域”!
方法区域是JVM的标准。永久生成是JDK1.7中热点虚拟机的特定实现和先前的方法区域。因此,元空间也是JDK1.8中方法区域的实现。
当虚拟机运行时,直接内存不是数据区域的一部分,也不是Java虚拟机规范中定义的内存区域。但是,这部分内存也经常使用,并且也可能导致OutofMemoryError异常。
在JDK 1.4中,添加了NIO(新输入/输出)类,并介绍基于通道的I/O方法。Java桩中存储的DirectByteBuffer对象被操作作为对此内存的引用。在某些情况下,这可以显着提高性能,因为避免使用Java堆和本地堆中的数据。您可以使用NIO来包装字节案#分配irect.Methods创建一堆外部内存,并使用不安全类应用底层。
显然,该计算机的直接内存分布不会受到Java桩的大小的限制,但是由于它是内存,因此它肯定会受到总内存(包括RAM和SWAP区域或分页文件)和处理器地址空间的限制。当服务器管理员配置虚拟机参数时,它将根据实际内存设置设置参数信息,例如-XMX,但通常会忽略直接内存,以便总存储器区域大于总存储器区域物理内存限制(包括物理和操作系统级别的限制),这导致导致导致导致导致导致导致的导致,这会导致导致领先的EmmoryError异常在动态扩展过程中发生。直接内存的最大值通过参数“ -xx:maxDirectMememememize”,当它超过最大值时,它也会抛出内存溢出的内存溢出指定的e。
JDK类提供了用于室外内存的应用程序的接口,并实现了底层。诸如Netty和Mina之类的框架提供的接口也基于ByteBuffer封装。
直接内存分配:
它用于分配直接内存,但是需要手动释放此内存,并且JVM不会恢复。幸运的是,不安全提供了另一种界面共隔离方法,以发布应用程序应用程序的应用程序。
在清洁剂中,将传递一个列表以维护每个回收堆的外部内存堆的线程对象(可运行),并且该方法中发生了回收操作。
最初开始一堆外部内存时,对象的参考关系如下:
其中,第一个是清洁剂类的静态变量。初始化时,清洁对象将被添加到Clener链接列表中,以形成与第一个的参考关系。参考等级用于保留需要回收的清洁对象。如果DirectByteBuffer对象没有参考,则可以回收直接BByTebuffer。
目前,只有清洁对象具有存储外部内存堆的唯一数据(启动地址,大小和容量)。清洁器类继承幻影。因此,清洁对象是一个对象。输入引用标题并触发清洁方法。
因此,清洁对象的干净方法具有两个主要功能:
如果JVM尚未执行FGC,则不能将无效的清洁器对象放置在参考器中,以便未释放外部内存,并且内存不会爆炸?
实际上,当初始化DirectByteBuffer对象时,如果当前室外存储器的当前条件很苛刻,则System.gc()将被积极地用于FGC。
它是一个专门用于管理最终修改的数据,以及在编译期间确定和保留在编译的类文件中的一些数据。字面恒定分配表格还可以存储运行时生成的常数,此类常数作为包装的一些基本类型(字节范围-128-12,字符范围0-127,短范围-128-127,整数范围-128-127,远距离范围128-127)。
常数池分为字符串常数池,类常数池和运行常数池。
在JDK1.6和以前的版本中,将字符串常数池放置在PERM Gen区域(即方法区域),并且逻辑包含在运行常数池中。
从JDK1.7版本开始,弦乐常数池从方法区域移动到堆。字符串方案的数量,将造成超ememoryError错误。
Hotspot VM中实现的字符串池函数是StringTable类,它是默认值1009的哈希表;每个热点VM中可用的字符串the仅仅是一个,并且由所有类共享。字符串的常数由一个字符组成,并放置在字符串台上。
在JDK1.6中,字符串表的长度为固定,长度为1009。因此,如果字符串池中有许多字符串,它将导致哈希冲突并导致链接列表太长。链接列表,这将导致绩效大幅下降;
在JDK1.7中,可以通过参数指定字符串的长度:
-xx:StringTablesize = 66666
在JDK1.6和以前的版本中,所有字符串常数都放在字符串池中;
在JDK1.7中,由于String.Intern()已更改,因此也可以在字符串池中的字符串对象中引用。如果不存在常数池,请在内存中找到它。如果内存中存在,请在常数池中的内存中保存对对象的引用。
JDK1.6:Internet()方法将首先查询常数池中是否已经存在。如果有的话,将返回常数池中的引用。还返回了常数池中此字符串实例的引用。
JDK1.7,然后:将首先确定当前字符串是否存在在常数池中。如果存在,请确定该常数是否存在还是常数。返回常数池常数参考;如果不存在,请在常数池中的堆内存中保存对对象的引用。
案件:
字符串str1 =“ a”;字符串str2 =“ b”;字符串str4 = str1 + str2;//此语句仅在堆中生成一个对象(str4)
该短语是由Java编译器优化的,实际上,它是使用StringBuilder(在桩中生成STR1和Str2对象)实现的。
在编译我们编写的每个Java类之后,形成了一个类文件;除了描述信息,包括类,字段,方法,接口等。在类文件中,还有一个信息池用于存储编译器生成的各种类型的文字和符号引用。
每个类文件都有一个类常数池,也称为静态常数池。
运行常数池存储在内存中,也就是说,在内存之后将类Constant_Pool表加载到版本中。分析是直接引用的。
执行课程时,必须加载,连接和初始化JVM,并且连接包括三个阶段:验证,准备和解析。当类加载到内存时,JVM将在类Constant Pool中存储在类中运行常数池。从中,我们可以看到运行常数池也是每个类别之一。在分析阶段,符号引用将被直接参考替换。解析过程将查询字符串常数池,这是我们上面提到的一致的。
JDK1.7和以前的运行常数池存在于方法区域中,然后移至元空间。
由于运行通常是从池中运行的方法是方法区域的一部分,因此它自然受到内存区域内存的限制。当常量池无法申请内存时,将会抛出OutofMemoryError异常。
在计算机科学中,文字是源代码中固定值的表示。几乎所有计算机编程语言都具有基本值的字面数量,例如:整数,浮点数和字符串;许多人还支持布尔类型和字符类型的价值的价值;甚至有一些列举的列举类型的类型和vim,记录和对象(例如复合类型)的类型也支持文字测量方法。
int i = 1;将整数1分配给int变量i,整数1是java字面数量;字符串S =“ ABC”;中间的ABC也是字面意思。
字面金额包括:
符号引用是一组描述引用目标的符号。该符号可以是任何形式的字面数量。只要使用它,就可以将其放置在目标的情况下对目标进行定位。例如,在Java中,Java类将被编译到类文件中。编译时,Java类不知道引用类的实际地址,因此只能用符号参考替换。例如,org.simple.peical类引用org.simple.simple.language class。在编译期间,人类类不知道语言类的实际记忆地址。因此,它只能使用符号org.simple.language来表示语言类的地址。
符号参考包括:
直接报价是说该程序可以在运行地址(类,对象,变量或方法等)时位于。在类加载的分析阶段中的直接参考将作为符号参考解析。
直接报价可以是:
相关文章:
如果您需要交流或文章错误,请直接留言。此外,我想喜欢,收集和关注,我将继续更新各种Java学习博客!