关闭

关闭

封号提示

内容

首页 java内存和 基本数据 类型.doc

java内存和 基本数据 类型.doc

java内存和 基本数据 类型.doc

上传者: song益鸿 2017-12-22 评分 0 0 0 0 0 0 暂无简介 简介 举报

简介:本文档为《java内存和 基本数据 类型doc》,可适用于IT/计算机领域,主题内容包含java内存和基本数据类型java内存和基本数据类型位Intelx最初拥有的位物理地址仅允许处理器寻址GB存储空间。后来添加了一种称为物理地址扩展(符等。

java内存和基本数据类型java内存和基本数据类型位Intelx最初拥有的位物理地址仅允许处理器寻址GB存储空间。后来添加了一种称为物理地址扩展(PhysicalAddressExtensionPAE)的特性将物理地址大小扩大到了位允许安装或寻址至多GBRAM。位的操作系统有GB虚拟地址空间可以映射到一个较大的物理地址范围如果您将大于GB的内存放入位Intel服务器中您将无法将所有内存直接映射到一个单一进程中。地址窗口扩展允许Windows进程将其位地址空间的一部分作为滑动窗口映射到较大的内存区域中。这意味着尽管您无法直接引用大于GB的内存但您仍然可以使用较大的内存区域。默认情况下位Windows拥有GB用户空间和GB内核空间可调整。当执行系统调用时内核需要访问其自己的内存和调用进程的内存。更小的用户空间意味着应用程序编程人员只能使用更少的内存空间。缩减内核区域可能导致一些问题比如能够同时登录的用户数量限制或能够运行的进程数量限制。程序共享库DLL在G内核空间中。尽管总体用户空间为GB但是不可能分配GB大的内存块因为共享库无法加载这么大的内存。本机内存泄漏或过度使用本机内存将导致不同的问题具体取决于您是耗尽了地址空间还是用完了物理内存。耗尽地址空间通常只会发生在位进程上因为最大GB的内存很容易分配完。位进程具有数百或数千GB的用户空间即使您特意消耗空间也很难耗尽这么大的空间。如果您确实耗尽了Java进程的地址空间那么Java运行时可能会出现一些陌生现象当在进程地址空间比物理内存大的系统上运行时内存泄漏或过度使用本机内存会迫使操作系统交换后备存储器来用作本机进程的虚拟地址空间。访问经过交换的内存地址比读取驻留(在物理内存中)的地址慢得多因为操作系统必须从硬盘驱动器拉取数据。可能会分配大量内存来用完所有物理内存和所有交换内存(页面空间)在Linux上这将触发内核内存不足(OOM)结束程序强制结束最消耗内存的进程。在Windows上与地址空间被占满时一样内存分配将会失败。同时如果尝试使用比物理内存大的虚拟内存显然在进程由于消耗内存太大而被结束之前就会遇到问题。系统将变得异常缓慢因为它会将大部分时间用于在内存与交换空间之间来回复制数据。当发生这种情况时计算机和独立应用程序的性能将变得非常糟糕从而使用户意识到出现了问题。当JVM的Java堆被交换出来时垃圾收集器的性能会变得非常差应用程序可能被挂起。如果一台机器上同时使用了多个Java运行时那么物理内存必须足够分配给所有Java堆。Java运行时是一个操作系统进程它会受到我在上一节中列出的硬件和操作系统局限性的限制。运行时环境提供的功能受一些未知的用户代码驱动这使得无法预测在每种情形中运行时环境将需要何种资源。Java堆是分配了对象的内存区域。大多数JavaSE实现都拥有一个逻辑堆一个物理堆可被划分为多个逻辑扇区具体取决于用于管理堆内存的垃圾收集(GC)算法。这些扇区通常实现为连续的本机内存块这些内存块受Java内存管理器(包含垃圾收集器)控制。大部分GC算法依赖于被分配为连续的内存块的堆因此不能在堆需要扩大时分配更多本机内存。所有堆内存必须预先保留。即时(JIT)编译器JIT编译器在运行时编译Java字节码来优化本机可执行代码。这极大地提高了Java运行时的速度并且支持Java应用程序以与本机代码相当的速度运行。字节码编译使用本机内存(使用方式与gcc等静态编译器使用内存来运行一样)但JIT编译器的输入(字节码)和输出(可执行代码)必须也存储在本机内存中。包含多个经过JIT编译的方法的Java应用程序会使用比小型应用程序更多的本机内存。类和类加载器Java应用程序由一些类组成这些类定义对象结构和方法逻辑。Java应用程序也使用Java运行时类库(比如javalangString)中的类也可以使用第三方库。这些类需要存储在内存中以备使用。存储类的方式取决于具体实现。SunJDK使用永久生成(permanentgenerationPermGen)堆区域。Java的IBM实现会为每个类加载器分配本机内存块并将类数据存储在其中。现代Java运行时拥有类共享等技术这些技术可能需要将共享内存区域映射到地址空间。要理解这些分配机制如何影响您Java运行时的本机内存占用您需要查阅该实现的技术文档。然而一些普遍的事实会影响所有实现。从最基本的层面来看使用更多的类将需要使用更多内存。(这可能意味着您的本机内存使用量会增加或者您必须明确地重新设置PermGen或共享类缓存等区域的大小以装入所有类)。记住不仅您的应用程序需要加载到内存中框架、应用服务器、第三方库以及包含类的Java运行时也会按需加载并占用空间。Java运行时可以卸载类来回收空间但是只有在非常严酷的条件下才会这样做。不能卸载单个类而是卸载类加载器随其加载的所有类都会被卸载。只有在以下情况下才能卸载类加载器:Java堆不包含对表示该类加载器的javalangClassLoader对象的引用。Java堆不包含对表示类加载器加载的类的任何javalangClass对象的引用。在Java堆上该类加载器加载的任何类的所有对象都不再存活(被引用)。需要注意的是Java运行时为所有Java应用程序创建的个默认类加载器(bootstrap、extension和application)都不可能满足这些条件因此任何系统类(比如javalangString)或通过应用程序类加载器加载的任何应用程序类都不能在运行时释放。许多JEE应用程序使用JavaServerPages(JSP)技术来生成Web页面。使用JSP会为执行的每个jsp页面生成一个类并且这些类会在加载它们的类加载器的整个生存期中一直存在这个生存期通常是Web应用程序的生存期。另一种生成类的常见方法是使用Java反射。反射的工作方式因Java实现的不同而不同,当使用javalangreflectAPI时Java运行时必须将一个反射对象(比如javalangreflectField)的方法连接到被反射到的对象或类。这可以通过使JNI)访问器来完成这种方法需要的用Java本机接口(JavaNativeInterface设置很少但是速度缓慢。也可以在运行时为您想要反射到的每种对象类型动态构建一个类。后一种方法在设置上更慢但运行速度更快非常适合于经常反射到一个特定类的应用程序。Java运行时在最初几次反射到一个类时使用JNI方法但当使用了若干次JNI方法之后访问器会膨胀为字节码访问器这涉及到构建类并通过新的类加载器进行加载。执行多次反射可能导致创建了许多访问器类和类加载器。保持对反射对象的引用会导致这些类一直存活并继续占用空间。因为创建字节码访问器非常缓慢所以Java运行时可以缓存这些访问器以备以后使用。一些应用程序和框架还会缓存反射对象这进一步增加了它们的本机内存占用。Java堆耗尽并不是造成javalangOutOfMemoryError的惟一原因。如果本机内存耗尽则会发生普通调试技巧无法解决的OutOfMemoryError。Java堆(每个Java对象在其中分配)是您在编写Java应用程序时使用最频繁的内存区域。JVM设计用于将我们与主机的特性隔离所以将内存当作堆来考虑再正常不过了。您一定遇到过Java堆OutOfMemoryError它可能是由于对象泄漏造成的也可能是因为堆的大小不足以存储所有数据Java应用程序在Java运行时的虚拟化环境中运行但是运行时本身是使用C之类的语言编写的本机程序它也会耗用本机资源包括本机内存。本机内存是可用于运行时进程的内存它与Java应用程序使用的java堆内存不同。每种虚拟化资源(包括Java堆和Java线程)都必须存储在本机内存中虚拟机在运行时使用的数据也是如此。这意味着主机的硬件和操作系统施加在本机内存上的限制会影响到Java应用程序的性能。处理器将数据流解释为要执行的指令它拥有一个或多个处理单元用于执行整数和浮点运算以及更高级的计算。处理器具有许多寄存器常快速的内存元素用作被执行的计算的工作存储寄存器大小决定了一次计算可使用的最大数值。处理器通过内存总线连接到物理内存。物理地址(处理器用于索引物理RAM的大小限制了可以寻址的内存。例如一个位物理地址可以寻址的地址)x到xFFFF的内存地址这个地址范围包括^=个惟一的内存位置。如果每个地址引用一个存储字节那么一个位物理地址将允许处理器寻址KB内存。处理器被描述为特定数量的数据位。这通常指的是寄存器大小但是也存在例外比如位指的是物理地址大小。对于桌面和服务器平台这个数字为、或对于嵌入式设备和微处理器这个数字可能小至。物理地址大小可以与寄存器带宽一样大也可以比它大或小。如果在适当的操作系统上运行大部分位处理器可以运行位程序。表一些流行处理器架构的寄存器和物理地址大小架构寄存器带宽(位)物理地址大小(位)(现代)Intelx具有物理地址扩展(PentiumPro和更高型号)x目前为位(以后将会增大)PPC在POWER上为位位位如果您编写无需操作系统直接在处理器上运行的应用程序您可以使用处理器可以寻址的所有内存(假设连接到了足够的物理RAM)。但是要使用多任务和硬件抽象等特性几乎所有人都会使用某种类型的操作系统来运行他们的程序。在Windows和Linux等多任务操作系统中有多个程序在使用系统资源。需要为每个程序分配物理内存区域来在其中运行。可以设计这样一个操作系统:每个程序直接使用物理内存并且可以可靠地仅使用分配给它的内存。一些嵌入式操作系统以这种方式工作但是这在包含多个未经过集中测试的应用程序的环境中是不切实际的因为任何程序都可能破坏其他程序或者操作系统本身的内存。虚拟内存允许多个进程共享物理内存而且不会破坏彼此的数据。在具有虚拟内存的操作系统(比如Windows、Linux和许多其他操作系统)中每个程序都拥有自己的虚拟地址空间一个逻辑地址区域其大小由该系统上的地址大小规定(所以桌面和服务器平台的虚拟地址空间为、或位)。进程的虚拟地址空间中的区域可被映射到物理内存、文件或任何其他可寻址存储。当数据未使用时操作系统可以在物理内存与一个交换区域(Windows上的页面文件或者Linux上的交换分区)之间移动它以实现对物理内存的最佳利用率。当一个程序尝试使用虚拟地址访问内存时操作系统连同片上硬件会将该虚拟地址映射到物理位置这个位置可以是物理RAM、一个文件或页面文件交换分区。如果一个内存区域被移动到交换空间那么它将在被使用之前加载回物理内存中。程序的每个实例以进程的形式运行。在Linux和Windows上进程是一个由受操作系统控制的资源(比如文件和套接字信息)、一个典型的虚拟地址空间(在某些架构上不止一个)和至少一个执行线程构成的集合。虚拟地址空间大小可能比处理器的物理地址大小更小。位Intelx最初拥有的位物理地址仅允许处理器寻址GB存储空间。后来添加了一种称为物理地址扩展(PhysicalAddressExtensionPAE)的特性将物理地址大小扩大到了位允许安装或寻址至多GBRAM。PAE允许操作系统将位的GB虚拟地址空间映射到一个较大的物理地址范围但是它不允许每个进程拥有GB虚拟地址空间。这意味着如果您将大于GB的内存放入位Intel服务器中您将无法将所有内存直接映射到一个单一进程中。地址窗口扩展(AddressWindowingExtension)特性允许Windows进程将其位地址空间的一部分作为滑动窗口映射到较大的内存区域中。Linux使用类似的技术将内存区域映射到虚拟地址空间中。这意味着尽管您无法直接引用大于GB的内存但您仍然可以使用较大的内存区域。地址空间被划分为用户空间和内核空间。内核是主要的操作系统程序包含用于连接计算机硬件、调度程序以及提供联网和虚拟内存等服务的逻辑。作为计算机启动序列的一部分操作系统内核运行并初始化硬件。一旦内核配置了硬件及其自己的内部状态第一个用户空间进程就会启动。如果用户程序需要来自操作系统的服务它可以执行一种称为系统调用的操作与内核程序交互内核程序然后执行该请求。系统调用通常是读取和写入文件、联网和启动新进程等操作所必需的。当执行系统调用时内核需要访问其自己的内存和调用进程的内存。因为正在执行当前线程的处理器被配置为使用地址空间映射来为当前进程映射虚拟地址所以大部分操作系统将每个进程地址空间的一部分映射到一个通用的内核内存区域。被映射来供内核使用的地址空间部分称为内核空间其余部分称为用户空间可供用户应用程序使用。可进行调整来为用户应用程序或内核提供更多空间。缩减内核区域可能导致一些问题比如能够同时登录的用户数量限制或能够运行的进程数量限制。更小的用户空间意味着应用程序编程人员只能使用更少的内存空间。默认情况下位Windows拥有GB用户空间和GB内核空间。在位Linux上默认设置为GB用户空间和GB内核空间。进程空间必须包含程序需要的所有内容包括程序本身和它使用的共享库(在Windows上为DDL在Linux上为so文件)。共享库不仅会占据空间使程序无法在其中存储数据它们还会使地址空间碎片化减少可作为连续内存块分配的内存。DLL在构建时设置了首选的加载地址:当加载DLL时它被映射到处于特定位置的地址空间除非该位置已经被占用在这种情况下它会加载到别处。WindowsNT最初设计时设置了GB可用用户空间这对于要构建来加载接近GB区域的系统库很有用使大部分用户区域都可供应用程序自由使用。当用户区域扩展到GB时系统共享库仍然加载接近GB数据(约为用户空间的一半)。尽管总体用户空间为GB但是不可能分配GB大的内存块因为共享库无法加载这么大的内存。简单的说:Java把内存划分成两种:一种是栈内存一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。当在一段代码块定义一个变量时Java就在栈中为这个变量分配内存空间当超过变量的作用域后Java会自动释放掉为该变量所分配的内存空间该内存空间可以立即被另作他用。堆内存用来存放由new创建的对象和数组。在堆中分配的内存由Java虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或对象后还可以在栈中定义一个特殊的变量让栈中这个变量的取值等于数组或对象在堆内存中的首地址栈中的这个变量就成了数组或对象的引用变量。引用变量就相当于是为数组或对象起的一个名称以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。具体的说:栈与堆都是Java用来在Ram中存放数据的地方。与C不同Java自动管理栈和堆程序员不能直接地设置栈或堆。Java的堆是一个运行时数据区,对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的堆的优势是可以动态地分配内存大小生存期也不必事先告诉编译器因为它是在运行时动态分配内存的Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是由于要在运行时动态分配内存存取速度较慢。栈的优势是存取速度比堆要快仅次于寄存器栈数据可以共享。但缺点是存在栈中的数据大小与生存期必须是确定的缺乏灵活性。栈中主要存放一些基本类型的变量(,int,short,long,byte,float,double,boolean,char)和对象句柄。栈有一个很重要的特殊*就是存在栈中的数据可以共享。假设我们同时定义:inta=intb=编译器先处理inta=首先它会在栈中创建一个变量为a的引用然后查找栈中是否有这个值如果没找到就将存放进来然后将a指向。接着处理intb=在创建完b的引用变量后因为在栈中已经有这个值便将b。这样就出现了a与b同时均指向的情况。这时如果再令a=直接指向那么编译器会重新搜索栈中是否有值如果没有则将存放进来并令a指向如果已经有了则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的因为这种情况a的修改并不会影响到b,它是由编译器完成的它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态会影响到另一个对象引用变量。String是一个特殊的包装类数据。可以用:Stringstr=newString("abc")Stringstr="abc"两种的形式来创建第一种是用new()来新建对象的它会在存放于堆中。每调用一次就会创建一个新的对象。而第二种是先在栈中创建一个对String类的对象引用变量str然后查找栈中有没有存放"abc"如果没有则将"abc"存放进栈并令str指向"abc"如果已经有"abc"则直接令str指向"abc"。基本数据类型Java中的简单类型从概念上分为四种:实数、整数、字符、布尔值。但是有一点需要说明的是Java里面只有八种原始类型其列表如下:实数:double、float整数:byte、short、int、long字符:char布尔值:boolean复杂类型和基本类型的内存模型本质上是不一样的简单数据类型的存储原理是这样的:所有的简单数据类型不存在"引用"的概念简单数据类型都是直接存储在内存中的内存栈上的数据本身的值就是存储在栈空间里面而Java语言里面只有这八种数据类型是这种存储模型而其他的只要是继承于Object类的复杂数据类型都是按照Java里面存储对象的内存模型来进行数据存储的使用Java内存堆和内存栈来进行这种类型的数据存储简单地讲"引用"是存储在有序的内存栈上的而对象本身的值存储在内存堆上的。)详细介绍:Java的简单数据讲解列表如下:int:int为整数类型在存储的时候用个字节存储范围为,,,到,,,在变量初始化的时候int类型的默认值为。short:short也属于整数类型在存储的时候用个字节存储范围为,到,在变量初始化的时候short类型的默认值为一般情况下因为Java本身转型的原因可以直接写为。long:long也属于整数类型在存储的时候用个字节存储范围为,,,,,,到,,,,,,在变量初始化的时候long类型的默认值为L或l也可直接写为。byte:byte同样属于整数类型在存储的时候用个字节来存储范围为到在变量初始化的时候byte类型的默认值也为。float:float属于实数类型在存储的时候用个字节来存储范围为位IEEEE单精度范围在变量初始化的时候float的默认值为f或。F在初始化的时候可以写double:double同样属于实数类型在存储的时候用个字节来存储范围为位IEEE双精度范围在变量初始化的时候double的默认值为。char:char属于字符类型在存储的时候用个字节来存储因为Java本身的字符集不是用ASCII码来进行存储是使用的位Unicode字符集它的字符范围即是Unicode的字符范围在变量初始化的时候char类型的默认值为'u'。boolean:boolean属于布尔类型在存储的时候不使用字节仅仅使用位来存储范围仅仅为和其字面量为true和false而boolean变量在初始化的时候变量的默认值为false。【】当整数类型的数据使用字面量赋值的时候默认值为int类型就是直接使用或者其他数字的时候值的类型为int类型所以当使用longa=这种赋值方式的时候JVM内部存在数据转换。【】当实数类型的数据使用字面量赋值的时候默认值为double类型就是当字面两出现的时候JVM会使用double类型的数据类型。【】从JDK开始Java里面出现了自动拆箱解箱的操作基于这点需要做一定的说明:对应原始的数据类型每种数据类型都存在一个复杂类型的封装类分别为Boolean、Short、Float、Double、Byte、Int、Long、Character这些类型都是内置的封装类这些封装类(Wrapper)提供了很直观的方法针对封装类的方法通过这种方法可以把需要说明的是每种封装类都有一个xxxValue()它引用的对象里面的值转化成为原始变量的值不仅仅如此每个封装类都还存在一个valueOf(String)的方法直接把字符串对象转换为相应的简单类型。在JDK之前没有存在自动拆解箱的操作即AutoBox操作所以在这之前是不能使用以下方式的赋值代码的:Integera=这种赋值方式不能够在JDK以及以下的JDK编译器中通过但是JDK出现了自动拆解箱的操作所以在JDK以上的编译器中以上的代码是可以通过的Java中简基本数据类型的转型:Java中的简单数据类型的转换分为两种:自动转换和强制转换)自动转换:当一个较"小"的数据和较"大"的数据一起运算的时候系统将自动将较"小"的数据转换为较"大"的数据再进行运算。在方法调用过程如果实际参数较"小"而函数的形参比较"大"的时候除非有匹配的方法否则会直接使用较"大"的形参函数进行调用。)强制转换:将"大"数据转换为"小"数据时可以使用强制类型转换在强制类型转换的时候必须使用下边这种语句:inta=(int)只是在上边这种类型转换的时候有可能会出现精度损失。关于类型的自动提升遵循下边的规则:所有的byte、short、char类型的值将提升为int类型如果有一个操作数是long类型计算结果是long类型如果有一个操作数是float类型计算结果是float类型如果有一个操作数是double类型计算结果是double类型自动类型转换图如下:byteshort(char)intlongfloatdouble如果是强制转换的时候就将上边的图反过来当两个类型进行自动转换的时候需要满足条件:【】这两种类型是兼容的【】目的类型的数值范围应该比源转换值的范围要大。而拓展范围就遵循上边的自动类型转换树当这两个条件都满足的时候拓展转换才会发生而对于几个原始类型转换过程根据兼容性boolean和char应该是独立的而其他六种类型是可以兼容的在强制转换过程唯独可能特殊的是char和int是可以转换的不过会使用char的ASCII码值比如:inta=(int)'a'a的值在转换过后输出的话值为Java提供了两个专门的类进行高精度运算:BigInteger与BigDecimal虽然Java原始变量都具有对应的封装类型但是这两个变量没有对应的原始类型而是通过方法来提供这两种类型的一些运算其含义为普通类型能够做的操作这两个类型对应都有只是因为精度过大可能效率不够高。货币运算使用BigDecimal代替double是一个很好的办法。在要求精度答案的计算任务里面一般慎用float和double如果在进行商务运算并且要求四舍五入或者简单的舍入行为使用BigDecimal可能更加方便。所以尽量避免在精度运算中使用float和double特别是我们常用的货币运算。string类型的字符串数组是可以无限的。字符串数组最大长度是多少一个数组最大的长度是一个int的最大值也就是而一个字符串在Java内部是使用char来表示的也就是说一个字符串的最大长度是不过这些都是理论值具体能放多少与JVM内存有关,可以在执行java命令时加上Xmxm就将JVM内存最大置为了G,默认情况下是MB都是java用来在RAM中存放数据的地方。与C不同java自动管理堆栈程序员不能直接设置堆栈。区别、栈中存放基本数据类型变量(int、float、boolean、char)和对象句柄堆中存放对象数据类型或者说类对象数据类型(String、基本数据类型对应的类类型(Integer、Double))、栈的存取速度比较快仅次于寄存器栈数据可以共享。但栈数据的大小和生存期必须是确定的缺乏灵活性。堆中的数据在*运行时*动态的分配内存存取速度慢有垃圾回收机制负责堆中的对象通过new、newarrary、anewarray和multianewarray等指令建立staticSwitchsw=newSwitch()声明为static的对象为静态对象静态对象在内存中保留着它的引用也就是说内存中有一块区域就是专门用来存放静态方法和变量的所以可以直接拿来用是全局对象。全局对象为类间通信和函数间通信提供了一种最简单的方式是类的静态成员上面已经提到基类及其派生类的所有对象都共享这个静态成员对象所以当需要在这些class之间或这些classobjects之间进行数据共享或通信时这样的静态成员无疑是很好的选择。栈对象的优势是在适当的时候自动生成又在适当的时候自动销毁不需而且栈对象的创建速度一般较堆对象快因为分配堆对象时会要程序员操心调用operatornew操作operatornew会采用某种内存空间搜索算法而该搜索过程可能是很费时间的产生栈对象则没有这么麻烦它仅仅需要移动栈顶指针就可以了。但是要注意的是通常栈空间容量比较小一般是MB~MB所以体积比较大的对象不适合在栈中分配。特别要注意递归函数中最好不要使用栈对象因为随着递归调用深度的增加所需的栈空间也会线性增加当所需栈空间不够时便会导致栈溢出这样就会产生运行时错误。Switchsw=newSwitch()堆对象其产生时刻和销毁时刻都要程序员精确定义也就是说程序员对堆对象的生命具有完全的控制权。我们常常需要这样的对象比如我们需要创建一个对象能够被多个函数所访问但是又不想使其成为全局的那么这个时候创建一个堆对象无疑是良好的选择然后在各个函数之间传递这个堆对象的指针便可以实现对该对象的共享。另外相比于栈空间堆的容量要大得多。实际上当物理内存不够时如果这时还需要生成新的堆对象通常不会产生运行时错误而是系统会使用虚拟内存来扩展实际的物理内存。javac对java文件进行处理最后生成Class文件的字节码表示时会同时生成一个常量池结构。在将数据放入常量池时会对重复的数据进行过滤(其实是一个Map)保证值保存一份。其实他是放在常量池里面的而不是栈里面如果引用是类的成员变量当类被实例化的时候该引用是随类的实例产生于堆内存中的那么如果该引用只是主方法中的一个局部变量呢此时保存在哪里呢局部变量是方法栈内存中的一个索引项其没有变量名称你所写的局部变量名称只存在与源代码局部变量是存放在方法栈的heap堆:用来存放new出来的东西成员变量stack栈:方法栈(包括局部变量)、操作数栈datasegment:静态变量字符串常量。codesegment:存放代码常量池方法区存放类与方法堆空间存放实例化的对象栈空间有两种一种是方法栈虚拟机会为每个线程所调用的方法申请空间而这个栈就是这些空间。另外一个是操作数栈两个局部变量或者成员变量需要进行处理的时候执行语句会吧这两个变量的值放入操作数栈中进行处理处理完成以后会将处理结果弹出栈。实例化对象的时候是怎样开辟内存空间的第二个问题当虚拟机生产对象的时候会申请内存空间(怎么申请的你去看汇编程序设计以及寄存器寻址方式)然后如果引用是静态成员变量则引用放在方法区中如果引用是成员变量则放在堆中如果引用是局部变量则成为局部变量索引(局部变量没有变量名称它只是一个索引项)局部变量是存放在方法栈的。引用对象内存怎么分配和指向第三个问题虚拟机规范没有规定引用应该去怎么实现如今应用大致有两种实现方式一种是引用直接就是一个指向堆内存的指针另外一个是引用指向方法区类对象映射表中的某个项映射表中的项再以指针的形式指向堆内存空间具体实现可能还有更多情况。特别声明::资料来源于互联网版权归属原作者:资料内容属于网络意见与本账号立场无关:如有侵权请告知立即删除。

职业精品

精彩专题

上传我的资料

热门资料

资料评价:

/ 18
所需积分:0 立即下载

意见
反馈

返回
顶部

Q