JVM虚拟机内存模型

JAVA虚拟机的根基,JVM内存模型详解 抽象 解析 程序计数器 程序计数器(Program Counter Register)是JVM中一块较小的内存区域,保存着当前线程执行的虚拟机字节码指令的内存地址(可以看作当前线程所执行的字节码的行号指示器)。 如果线程执行的是java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址(可以理解为上图所示的行号),如果正在执行的是native方法,这个计数器的值为undefined。 JVM... 阅读详情

java虚拟机运行时内存主要包括:程序计数器、虚拟机栈、本地方法栈、java堆、方法区(包含运行时方法区)以及直接内存几个部分。

下面分别介绍几个部分:如下图所示(图片源自网络)



image

1.  程序计数器(Program Counter Register) ,很小的一块内存空间,当前线程执行的字节码的行号指示器,执行命令的指令指针。

字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、

线程恢复等基础功能都需要依赖这个计数器来完成。由于Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现

的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能
恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,这类内存区域为“线程私有”的内存。

如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie 方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在Java 虚拟机规范中没有规定任何OutOfMemoryError 情况的区域。

      2. 虚拟机栈(VM stack),是java方法执行的内存模型,也是线程私有的。

每个方法被执行的时候都会创建一个栈帧(Stack Frame )用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。经常有人把Java 内存区分为堆内存(Heap)和栈内存(Stack),这种分法比较粗糙,只能说明大多数程序员最关注的、与对象内存分配关系最密切的内存区域是这两块。局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,它不等同于对象本身,根据不同的虚拟

机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置)和 returnAddress 类型(指向了一条字节码指令的地址)。其中64 位长度的long 和double 类型的数据会占用2 个局部变量空间(Slot),其余的数据类型只占用1 个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

在Java 虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常;

如果虚拟机栈可以动态扩展(当前大部分的Java 虚拟机都可动态扩展,只不过Java 虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError 异常。

3. 本地方法栈(Native method stack)

虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。虚拟机规范中对本地方法栈中的方法使用的语

言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot 虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError 和OutOfMemoryError异常。

4. 堆(Heap), Java 虚拟机所管理的内存中最大的一块,所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在 Java 虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配,但是随着技术发展现在对象分配在堆上也渐渐变得不是那么 “绝对 ”了。

Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”。如果从内存回收的角度看,由于现在收集器基本都是采用的分代收集算法,所以Java 堆中还可以细分为:新生代和老年代;再细致一点的有Eden 空间、From Survivor 空间、To Survivor 空间等。如果从内存分配的角度看,线程共享的Java 堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。

根据Java 虚拟机规范的规定,Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。在实现时,既可以实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(通过-Xmx和-Xms 控制)。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常。

5. 方法区 ( Method Area ),与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

很多人愿意把方法区称为“永久代”(Permanent Generation),本质上两者并不等价,仅仅是因为HotSpot 虚拟机的设计团队选择把GC 分代收集扩展至方法区,或者说使用永久代来实现方法区而已。对于其他虚拟机(如BEA JRockit、IBM J9 等)来说是不存在永久代的概念的。即使是HotSpot 虚拟机本身,根据官方发布的路线图信息,现在也有放弃永久代并“搬家”至Native Memory 来实现方法区的规划了。Java 虚拟机规范对这个区域的限制非常宽松,除了和Java 堆一样不需要连续的内

存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是有必要的。Java 虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError 异常。

运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant PoolTable),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。Java 虚拟机对Class 文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会被虚拟机认可、装载和执行。但对于运行时常量池,Java 虚拟机规范没有做任何细节的要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域。不过,一般来说,除了保存Class 文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。运行时常量池相对于Class 文件常量池的另外一个重要特征是具备动态性,Java 语言并不要求常量一定只能在编译期产生,也就是并非预置入Class 文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String 类的intern() 方法。既然运行时常量池是方法区的一部分,无法申请到内存时会抛出OutOfMemoryError 异常。

6. 接内存存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError 异常出现,所以我们放到这里一起讲解。在JDK 1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)

与缓冲区(Buffer)的I/O 方式,它可以使用Native 函数库直接分配堆外内存,然后通过一个存储在Java 堆里面的DirectByteBuffer 对象作为这块内存的引用进行

操作。这样能在一些场景中显著提高性能,因为避免了在Java 堆和Native 堆中来回复制数据。显然,本机直接内存的分配不会受到Java 堆大小的限制,但是,既然是内存,则肯定还是会受到本机总内存(包括RAM 及SWAP 区或者分页文件)的大小及处理器寻址空间的限制。服务器管理员配置虚拟机参数时,一般会根据实际内存设置-Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),从而导致动态扩展时出现OutOfMemoryError异常。


在Java 语言中,对象访问是如何进行的?对象访问在Java 语言中无处不在,是最普通的程序行为,但即使是最简单的访问,也会却涉及Java 栈、Java 堆、方法区这三个最重要内存区域之间的关联关系,如下面的这句代码:

Object obj = new Object();

假设这句代码出现在方法体中,那“Object obj”这部分的语义将会反映到Java 栈的本地变量表中,作为一个reference 类型数据出现。而“new Object()”这部分的语义

将会反映到Java 堆中,形成一块存储了Object 类型所有实例数据值(Instance Data,对象中各个实例字段的数据)的结构化内存,根据具体类型以及虚拟机实现的对象内存布局(Object Memory Layout)的不同,这块内存的长度是不固定的。另外,在Java 堆中还必须包含能查找到此对象类型数据(如对象类型、父类、实现的接口、方法等)的地址信息,这些类型数据则存储在方法区中。由于reference 类型在Java 虚拟机规范里面只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位,以及访问到Java 堆中的对象的具体位置,因此不同虚拟机实现的对象访问方式会有所不同,主流的访问方式有两种:使用句柄和直接

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

 

 

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

 

 

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



=============================================================
下面部分内容是转载的,讲的挺详细的。

内存区域

    Java虚拟机在执行Java程序的过程中会把他所管理的内存划分为若干个不同的数据区域。Java虚拟机规范将JVM所管理的内存分为以下几个运行时数据区:程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区。下面详细阐述各数据区所存储的数据类型。




   程序计数器(Program Counter Register)

    一块较小的内存空间,它是当前线程所执行的字节码的行号指示器,字节码解释器工作时通过改变该计数器的值来选择下一条需要执行的字节码指令,分支、跳转、循环等基础功能都要依赖它来实现。每条线程都有一个独立的的程序计数器,各线程间的计数器互不影响,因此该区域是线程私有的。

    当线程在执行一个Java方法时,该计数器记录的是正在执行的虚拟机字节码指令的地址,当线程在执行的是Native方法(调用本地操作系统方法)时,该计数器的值为空。另外,该内存区域是唯一一个在Java虚拟机规范中么有规定任何OOM(内存溢出:OutOfMemoryError)情况的区域。

 

   Java虚拟机栈(Java Virtual Machine Stacks)

   该区域也是线程私有的,它的生命周期也与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧,栈它是用于支持续虚拟机进行方法调用和方法执行的数据结构。对于执行引擎来讲,活动线程中,只有栈顶的栈帧是有效的,称为当前栈帧,这个栈帧所关联的方法称为当前方法,执行引擎所运行的所有字节码指令都只针对当前栈帧进行操作。栈帧用于存储局部变量表、操作数栈、动态链接、方法返回地址和一些额外的附加信息。在编译程序代码时,栈帧中需要多大的局部变量表、多深的操作数栈都已经完全确定了,并且写入了方法表的Code属性之中。因此,一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。

在Java虚拟机规范中,对这个区域规定了两种异常情况:

    1、如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。

    2、如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

    这两种情况存在着一些互相重叠的地方:当栈空间无法继续分配时,到底是内存太小,还是已使用的栈空间太大,其本质上只是对同一件事情的两种描述而已。在单线程的操作中,无论是由于栈帧太大,还是虚拟机栈空间太小,当栈空间无法分配时,虚拟机抛出的都是StackOverflowError异常,而不会得到OutOfMemoryError异常。而在多线程环境下,则会抛出OutOfMemoryError异常。

    下面详细说明栈帧中所存放的各部分信息的作用和数据结构。 

   1、局部变量表

   局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量,其中存放的数据的类型是编译期可知的各种基本数据类型、对象引用(reference)和returnAddress类型(它指向了一条字节码指令的地址)。局部变量表所需的内存空间在编译期间完成分配,即在Java程序被编译成Class文件时,就确定了所需分配的最大局部变量表的容量。当进入一个方法时,这个方法需要在栈中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

    局部变量表的容量以变量槽(Slot)为最小单位。在虚拟机规范中并没有明确指明一个Slot应占用的内存空间大小(允许其随着处理器、操作系统或虚拟机的不同而发生变化),一个Slot可以存放一个32位以内的数据类型:boolean、byte、char、short、int、float、reference和returnAddresss。reference是对象的引用类型,returnAddress是为字节指令服务的,它执行了一条字节码指令的地址。对于64位的数据类型(long和double),虚拟机会以高位在前的方式为其分配两个连续的Slot空间。

    虚拟机通过索引定位的方式使用局部变量表,索引值的范围是从0开始到局部变量表最大的Slot数量,对于32位数据类型的变量,索引n代表第n个Slot,对于64位的,索引n代表第n和第n+1两个Slot。

    在方法执行时,虚拟机是使用局部变量表来完成参数值到参数变量列表的传递过程的,如果是实例方法(非static),则局部变量表中的第0位索引的Slot默认是用于传递方法所属对象实例的引用,在方法中可以通过关键字“this”来访问这个隐含的参数。其余参数则按照参数表的顺序来排列,占用从1开始的局部变量Slot,参数表分配完毕后,再根据方法体内部定义的变量顺序和作用域分配其余的Slot。

    局部变量表中的Slot是可重用的,方法体中定义的变量,作用域并不一定会覆盖整个方法体,如果当前字节码PC计数器的值已经超过了某个变量的作用域,那么这个变量对应的Slot就可以交给其他变量使用。这样的设计不仅仅是为了节省空间,在某些情况下Slot的复用会直接影响到系统的而垃圾收集行为。

    2、操作数栈

    操作数栈又常被称为操作栈,操作数栈的最大深度也是在编译的时候就确定了。32位数据类型所占的栈容量为1,64为数据类型所占的栈容量为2。当一个方法开始执行时,它的操作栈是空的,在方法的执行过程中,会有各种字节码指令(比如:加操作、赋值元算等)向操作栈中写入和提取内容,也就是入栈和出栈操作。

    Java虚拟机的解释执行引擎称为“基于栈的执行引擎”,其中所指的“栈”就是操作数栈。因此我们也称Java虚拟机是基于栈的,这点不同于Android虚拟机,Android虚拟机是基于寄存器的。

    基于栈的指令集最主要的优点是可移植性强,主要的缺点是执行速度相对会慢些;而由于寄存器由硬件直接提供,所以基于寄存器指令集最主要的优点是执行速度快,主要的缺点是可移植性差。

    3、动态连接

    每个栈帧都包含一个指向运行时常量池(在方法区中,后面介绍)中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。Class文件的常量池中存在有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用,一部分会在类加载阶段或第一次使用的时候转化为直接引用(如final、static域等),称为静态解析,另一部分将在每一次的运行期间转化为直接引用,这部分称为动态连接。

    4、方法返回地址

    当一个方法被执行后,有两种方式退出该方法:执行引擎遇到了任意一个方法返回的字节码指令或遇到了异常,并且该异常没有在方法体内得到处理。无论采用何种退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行。方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。一般来说,方法正常退出时,调用者的PC计数器的值就可以作为返回地址,栈帧中很可能保存了这个计数器值,而方法异常退出时,返回地址是要通过异常处理器来确定的,栈帧中一般不会保存这部分信息。

    方法退出的过程实际上等同于把当前栈帧出站,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,如果有返回值,则把它压入调用者栈帧的操作数栈中,调整PC计数器的值以指向方法调用指令后面的一条指令。

 

   本地方法栈(Native Method Stacks)

    该区域与虚拟机栈所发挥的作用非常相似,只是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为使用到的本地操作系统(Native)方法服务。

 

   Java堆(Java Heap)

    Java Heap是Java虚拟机所管理的内存中最大的一块,它是所有线程共享的一块内存区域。几乎所有的对象实例和数组都在这类分配内存。Java Heap是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”。

    根据Java虚拟机规范的规定,Java堆可以处在物理上不连续的内存空间中,只要逻辑上是连续的即可。如果在堆中没有内存可分配时,并且堆也无法扩展时,将会抛出OutOfMemoryError异常。   

 

   方法区(Method Area)

    方法区也是各个线程共享的内存区域,它用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区域又被称为“永久代”,但这仅仅对于Sun HotSpot来讲,JRockit和IBM J9虚拟机中并不存在永久代的概念。Java虚拟机规范把方法区描述为Java堆的一个逻辑部分,而且它和Java Heap一样不需要连续的内存,可以选择固定大小或可扩展,另外,虚拟机规范允许该区域可以选择不实现垃圾回收。相对而言,垃圾收集行为在这个区域比较少出现。该区域的内存回收目标主要针是对废弃常量的和无用类的回收。运行时常量池是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Class文件常量池),用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。运行时常量池相对于Class文件常量池的另一个重要特征是具备动态性,Java语言并不要求常量一定只能在编译期产生,也就是并非预置入Class文件中的常量池的内容才能进入方法区的运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的是String类的intern()方法。

    根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

 

    直接内存(Direct Memory)

直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,它直接从操作系统中分配,因此不受Java堆大小的限制,但是会受到本机总内存的大小及处理器寻址空间的限制,因此它也可能导致OutOfMemoryError异常出现。在JDK1.4中新引入了NIO机制,它是一种基于通道与缓冲区的新I/O方式,可以直接从操作系统中分配直接内存,即在堆外分配内存,这样能在一些场景中提高性能,因为避免了在Java堆和Native堆中来回复制数据。关于NIO的详细使用可以参考我的Java网络编程系列中关于NIO的相关文章。


内存溢出

    下面给出个内存区域内存溢出的简单测试方法


    这里有一点要重点说明,在多线程情况下,给每个线程的栈分配的内存越大,反而越容易产生内存溢出异常。操作系统为每个进程分配的内存是有限制的,虚拟机提供了参数来控制Java堆和方法区这两部分内存的最大值,忽略掉程序计数器消耗的内存(很小),以及进程本身消耗的内存,剩下的内存便给了虚拟机栈和本地方法栈,每个线程分配到的栈容量越大,可以建立的线程数量自然就越少。因此,如果是建立过多的线程导致的内存溢出,在不能减少线程数的情况下,就只能通过减少最大堆和每个线程的栈容量来换取更多的线程。

    另外,由于Java堆内也可能发生内存泄露(Memory Leak),这里简要说明一下内存泄露和内存溢出的区别:

    内存泄露是指分配出去的内存没有被回收回来,由于失去了对该内存区域的控制,因而造成了资源的浪费。Java中一般不会产生内存泄露,因为有垃圾回收器自动回收垃圾,但这也不绝对,当我们new了对象,并保存了其引用,但是后面一直没用它,而垃圾回收器又不会去回收它,这边会造成内存泄露,

    内存溢出是指程序所需要的内存超出了系统所能分配的内存(包括动态扩展)的上限。


对象实例化分析

    对内存分配情况分析最常见的示例便是对象实例化:

Object obj = new Object();

   这段代码的执行会涉及java栈、Java堆、方法区三个最重要的内存区域。假设该语句出现在方法体中,及时对JVM虚拟机不了解的Java使用这,应该也知道obj会作为引用类型(reference)的数据保存在Java栈的本地变量表中,而会在Java堆中保存该引用的实例化对象,但可能并不知道,Java堆中还必须包含能查找到此对象类型数据的地址信息(如对象类型、父类、实现的接口、方法等),这些类型数据则保存在方法区中。

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

    通过句柄池访问的方式如下:


   通过直接指针访问的方式如下:


    这两种对象的访问方式各有优势,使用句柄访问方式的最大好处就是reference中存放的是稳定的句柄地址,在对象呗移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改。使用直接指针访问方式的最大好处是速度快,它节省了一次指针定位的时间开销。目前Java默认使用的Hot Spot虚拟机采用的便是是第二种方式进行对象访问的。


西门子S7-1200的PID应用(恒温热水器) 物料清单:1200PLC一台,模拟量输入模块SM1231(PLC自带的输入通道不支持4-20mA电流输入)一个,PT100一个,温度变送器,热得快,固态继电器。 第一步,硬件接线; 第二步,新建1200工程,添加PLC和模拟量输入模块,修改模块的模拟量输入类型为4-20mA,模拟量模块的IO地址为96-103(8个字); 第三步,新建循环组织块OB30,循环时间选择默认点1... 阅读详情

相关推荐

Android系统编译之Communication error with Jack server (35), try ‘jack-diagnose‘ or see Jack server log

jack server failed场景个人分析网上分析分析1分析2原因1:权限问题原因2:端口占用原因3:删除 TLSv1, TLSv1.1测试结论解决方案说明相关链接 场景 在进行Android系统开发时,在liunx编译时发生问题,描述如下: ninja: build stopped: subcommand failed. build/core/ninja.mk:148: recipe for target 'ninja_wrapper' failed make: *** [ninja_wrapper

weixin_43194854的博客 2401

【深入Java虚拟机】之一:Java内存区域与内存溢出

Java虚拟机在执行Java程序的过程中会把他所管理的内存划分为若干个不同的数据区域。Java虚拟机规范将JVM所管理的内存分为以下几个运行时数据区:程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区。下面详细阐述各数据区所存储的数据类型。 程序计数器(Program Counter Register) 一块较小的内存空间,它是当前线程所执行的字节码的行号指示器,字节码解释器工作时通过改变该计数器的值来选择下一条需要执行的字节码指令,分支、跳转、循环等基础功能都要依赖它来实现。每条

兰亭风雨的专栏 5万+

别再手动调参了!用BERTopic分析500篇论文摘要,我总结了这份超全参数调优指南

本文详细介绍了如何通过BERTopic参数调优从500篇论文摘要中挖掘高质量主题。从文档嵌入、降维到聚类,每个环节的关键参数设置都直接影响主题分析效果。文章提供了学术文本特有的调优技巧,包括预处理、主题多样性与专注度的平衡,以及评估指标与迭代优化方法,帮助研究者高效完成NLP主题分析任务。

weixin_31235909的博客 214

【深入理解JAVA虚拟机学习笔记三】栈溢出,堆溢出,直接内存溢出,内存泄漏,以及异常信息

由于在Hotspot虚拟机中中不区分虚拟机栈和本地方法栈,因此通过-Xoss修改参数是无效的,可以通过修改-Xss设定。 如果线程请求的栈深度大于虚拟机允许的最大深度,将抛出StackOverflowError异常。 如果虚拟机在扩展栈时无法申请到足够的内存空间,将抛出OutOfMemoryError异常。 这两种异常有一些重叠的部分:当栈空间无法继续分配时,到底是内存太小,还是已经使用的栈空间过...

努力努力再努力m 1313

从Palantir到AI时代:Forward Deployed Engineer模式的深度解析

《从Palantir到AI时代:FDE模式的创新与挑战》摘要:Palantir开创的前置部署工程师(FDE)模式正在成为AI创业公司的标配。该模式通过现场工程师深入了解客户需求,填补产品与实际应用间的鸿沟,颠覆了传统SaaS规模化路径。核心优势在于将定制化服务转化为产品发现机制,特别适合高度异质化的AI市场。成功关键在于平衡定制与标准化,通过合同价值增长、产品杠杆效应等独特指标衡量成效。FDE人才需要兼具领域洞察力与快速原型能力。这一模式表明,在AI等新兴领域,深入客户现场可能比单纯追求技术突破更能创造商业

老孙 | Ethan Sun 的博客:AI 智能体与 AI 原生软件的工程实践 4531

土地利用数据从1972到2023:如何利用Landsat和Sentinel数据构建长期变化监测模型

本文详细解析了如何利用1972至2023年的Landsat和Sentinel遥感数据构建土地利用长期变化监测模型。通过多源数据融合策略、时间序列预处理流程和深度学习算法,实现高精度的土地利用分类与变化检测,为生态评估和城市规划提供科学依据。文章还探讨了验证方法和实际应用案例,展示了长期遥感数据在环境建模中的独特价值。

weixin_28720573的博客 443

Java常见内存溢出异常分析

Java虚拟机规范规定JVM的内存分为了好几块,比如堆,栈,程序计数器,方法区等,而Hotspot jvm的实现中,将堆内存分为了三部分,新生代,老年代,持久带,其中持久带实现了规范中规定的方法区,而内存模型中不同的部分都会出现相应的OOM错误,接下来我们就分开来讨论一下。

任何技能都是从模仿开始,逐步升华。 2485

IDM更改下载路径的详细指南

Internet Download Manager(IDM)是一款功能全面的下载加速工具,它支持多种浏览器和协议,能够显著提升下载速度,同时提供断点续传、多线程下载等实用功能。IDM的用户界面简洁明了,操作便捷,使得用户能够轻松管理下载任务。此外,IDM还支持自动分类下载文件、定时下载等高级功能,进一步提升了用户的下载体验。通过本文的介绍,相信用户已经掌握了如何在IDM中更改下载路径的方法。这一功能不仅提升了下载效率和文件管理便捷性,还满足了用户的个性化需求。

nntxthml的博客 1762

JAVA 内存泄露详解(原因、例子及解决)

转载请注明出处:http://blog.youkuaiyun.com/anxpp/article/details/51325838,谢谢! Java的一个重要特性就是通过垃圾收集器(GC)自动管理内存的回收,而不需要程序员自己来释放内存。理论上Java中所有不会再被利用的对象所占用的内存,都可以被GC回收,但是Java也存在内存泄露,但它的表现与C++不同。 JAVA 中的内存管...

anxpp的博客 12万+

Revit Dynamo实战:用Excel数据批量生成桥梁模型(附自适应族技巧)

本文详细介绍了如何利用Revit Dynamo结合Excel数据实现桥梁参数化建模,重点讲解了数据驱动建模、自适应族优化及大型项目性能管理三大核心技巧。通过结构化Excel数据、高级自适应族创建和分块处理策略,显著提升桥梁建模效率与设计变更响应能力。

weixin_42520025的博客 387

谷歌倾斜摄影数据获取以及转换3DTiles介绍

解析谷歌倾斜模型数据,再一键设置无人值守的情况下,快速将谷歌倾斜摄影模型数据转成3DTiles数据,并在Cesium上进行流畅漫游缩放显示,效果优于官方3DTiiles格式数据

cyber_room的博客 5335

C++基础教程面向对象(学习笔记(69))

功能模板专业化 在实例化给定类型的函数模板时,编译器会模板化模板化函数的副本,并将模板类型参数替换为变量声明中使用的实际类型。这意味着特定函数将具有每个实例类型的相同实现细节(仅使用不同类型)。虽然大多数情况下,这正是您想要的,但偶尔会出现对特定数据类型实现略有不同的模板化函数有用的情况。 模板专业化是实现这一目标的一种方法。 我们来看一个非常简单的模板类: template <class ...

qq_41879485的博客 195

LPDDR6与LPDDR5 ZQ Calibration技术探讨

LPDDR6与LPDDR5 ZQ Calibration技术探讨

zilan23的博客 1098

【Java】虚拟机(JVM)内存模型全解析

JVM 虚拟机在执行 Java 程序的过程中,会把它管理的内存划分成若干个不同的区域,每个区域有各自的不同的用途、创建方式及管理方式。有些区域随着虚拟机的启动一直存在,有些区域则随着用户线程的启动和结束而建立和销毁,这些共同组成了 Java 虚拟机的,也被称为。

weixin_71491685的博客 1825

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

java虚拟机与jvm内存模型

1.Java虚拟机本质与编译器由来 Java虚拟机jvm(一个c++程序而已,当然也有其他语法实现的)其实是一个进程虚拟机--上面跑进程的(,普通服务器虚拟机是跑操作系统的),启动一个java程序就是启动一个java虚拟机上面跑这个java程序,这个启动的java虚拟机对操作系统来说其实就是一个(c++)进程,这个进程会调用本地方法(C/C++/汇编语言编写,编译成和处理器相关的机

le119126的专栏 5408

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Java虚拟机 jvm内存模型

1JVM体系结构 2 类加载器 2.1 类加载器子系统 2.2 执行步骤 2.2.1 加载 2.2.2 链接 2.2.3 初始化 3 JVM运行时数据区域 3.1 方法区 MethodArea 3.2 Java堆Heap 3.3 虚拟机栈 3.3.1栈帧 3.3.2 局部变量表 3.3.3操作数栈 3.3.4动态链接 3.3.5 方法出口 3.4程序计数器 3.5本地方法栈 3.6 直接内存 4 执行引擎 5 本地方法.........

周天祥的博客 1161

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

[JVM|内存模型] Java虚拟机的内存模型?也就这7个而已

JVM内存模型 Java虚拟机所管理的内存包括以下 7个 运行时数据区域: 1. 程序计数器 (Program Counter Register) 一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器 线程私有的内存 值得注意的是:《Java虚拟机规范》中,唯一一个没有规定任何OutOfMemoryError情况的区域!!! 2. Java虚拟机栈 (VM Stack) Java方法执行的线程内存模型 为虚拟机执行Java方法(也就是字节码)服务 线程私有的内存 其生命周期与线程相同

喜欢前端的后端 MelodyJerry 8474

【Java虚拟机】JVM内存模型

JVM的运行时内存主要分为Java虚拟机栈,堆,本地方法栈,程序计数器,元空间五个部分,还有一部分是直接内存,是操作系统的本地内存,也是可以直接操作的。每个线程都有一个独立的虚拟机栈,并且在方法执行前都会在栈中创建一个栈帧,用来存储该方法的一些信息。堆是JVM中最大的一块区域,它是所有线程共享的,用来存储对对象的实例。每当遇到一个new关键字时,都会在堆中为其分配一块内存与虚拟机栈类似,本地方法栈是服务于本地方法的,当方法执行时也会创建一个栈帧。程序计数器可以看作是Java程序运行字节码文件的行号指示器。它

2302_81153890的博客 836

Java虚拟机 JVM内存模型介绍

JVM内存模型包含:程序计数器、虚拟机栈、本地方法栈、堆和方法区。 其中程序计数器、虚拟机栈、本地方法栈是每个线程私有的,而堆和方法区是所有线程共享的区域。

qq_42699603的博客 723

JVM虚拟机学习二、虚拟机内存模型(JDK1.8)

JVM虚拟机学习二、虚拟机内存模型(JDK1.8) 基于JDK1.8,HostPot虚拟机 JVM运行时内存模型(1.8) 先说说与JDK1.7之前的区别: 没有了方法区,取而带之的是元空间(这么说不标准,方法区只是JVM规范的概念,并不实际存在。) 原来方法区中的运行时常量池中的字符串常量池,静态变量,都存在于堆中了。(注意是字符串常量池存放于堆中,并不是运行时常量池!) 方法区中其余的(例...

qq_38238296的博客 1517

02-JVM虚拟机栈及内存模型

JVM虚拟机栈及内存模型 1、虚拟机栈 虚拟机栈就是一个线程里方法链执行的入栈出栈的一个过程,一个方法的调用对应一个栈帧。 栈帧中有些什么? 1、局部变量表:方法中定义的局部变量以及方法的参数存储在这张表中,局部变量表中的变量不可以直接使用,如需要使用的话,必须通过相关指令将其加载至操作数栈中作为操作数使用。 2、操作数栈:以压栈和出栈的方式存储操作数的 3、动态链接:每个栈帧都包含了一个指向运行...

shuaidong910402的博客 392

JVM虚拟机【八股篇】:内存模型

本文深入解析了Java虚拟机(JVM)的核心架构与内存模型。JVM主要由类加载子系统、运行时数据区、执行引擎和本地方法接口组成,协同实现Java程序的加载与执行。重点分析了运行时数据区的内存划分,包括线程私有的程序计数器、虚拟机栈、本地方法栈,以及线程共享的堆和方法区。特别探讨了堆内存的分代设计(新生代和老年代)及其垃圾回收机制,并总结了各内存区域的OOM异常类型及产生原因。通过栈帧结构的剖析,揭示了方法调用的底层实现机制。文章为理解JVM工作原理和性能调优提供了系统性的知识框架。

感谢阅读。 601

JVM虚拟机(一)介绍、JVM内存模型、JAVA内存模型,堆区、虚拟机栈、本地方法栈、方法区、常量池

深入理解Java语言:了解JVM的工作原理可以帮助你更深入地理解Java语言的运行机制,包括字节码的编译和执行过程;以及JVM的一些概念和技术,如垃圾收集、内存管理等。 改进代码质量:了解JVM的内存模型和并发模型可以帮助你编写更高质量的代码,避免死锁和竞态条件等问题。 性能优化:掌握JVM的知识能让你更有效地进行性能调优。你可以分析和理解垃圾收集器的行为,优化内存使用,减少延迟和提高吞吐量。 故障排查:当遇到内存泄漏、栈溢出、CPU飙高或其他JVM相关的问题时,对JVM的了解可以帮助你快速定位和解决问题

m0_52767002的博客 1049

Java虚拟机—Java8内存模型JVM(整理版)

对于Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要手动释放内存,不容易出现内存泄露和内存溢出问题。一旦出现内存泄露和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,排查错误将会异常艰难。Java虚拟机模型(Java Virtual Model,JVM),jvm的内部结构如下图所示。Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销

javalingyu的博客 3912

深入解析Java虚拟机(JVM)内存模型-全面掌握JVM内存管理

JVM内存模型是Java虚拟机管理内存的方式,它定义了Java程序在运行时如何存储和访问数据。理解JVM内存模型对于编写高效的Java代码、诊断内存相关问题以及优化应用性能至关重要。堆(Heap)方法区(Method Area)程序计数器(Program Counter Register)本地方法栈(Native Method Stack)虚拟机栈(VM Stack)接下来,我们将详细介绍每个区域的特点和作用。

一个8年大数据开发工程师的碎碎念 2072

JVM虚拟机内存模型简单认识

jvm内存模型和结构

weixin_47782546的博客 196
上一篇: android 应用动态加载机制2--资源加载机制和Activity生命周期管理
下一篇: java虚拟机Class类文件的结构
cding1818
博客等级 码龄17年 963粉丝 154原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值