在JVM中,静态属性保存在Stack指令内存区,动态属性保存在Heap数据内存区。本文将从JVM的角度来讲解Java虚拟机的这一机制。
在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认识Stack和Heap,并通过这些原理认清Java中静态方法和静态属性的问题。
一般,JVM的内存分为两部分:Stack和Heap。
Stack(栈)是JVM的内存指令区。Stack管理很简单,push一定长度字节的数据或者指令,Stack指针压栈相应的字节位移;pop一定字节长度数据或者指令,Stack指针弹栈。Stack的速度很快,管理很简单,并且每次操作的数据或者指令字节长度是已知的。所以Java 基本数据类型,Java 指令代码,常量都保存在Stack中。
Heap(堆)是JVM的内存数据区。Heap 的管理很复杂,每次分配不定长的内存空间,专门用来保存对象的实例。在Heap 中分配一定的内存来保存对象实例,实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在Stack中),在Heap 中分配一定的内存保存对象实例和对象的序列化比较类似。而对象实例在Heap 中分配好以后,需要在Stack中保存一个4字节的Heap 内存地址,用来定位该对象实例在Heap 中的位置,便于找到该对象实例。
由于Stack的内存管理是顺序分配的,而且定长,不存在内存回收问题;而Heap 则是随机分配内存,不定长度,存在内存分配和回收的问题;因此在JVM中另有一个GC进程,定期扫描Heap ,它根据Stack中保存的4字节对象地址扫描Heap ,定位Heap 中这些对象,进行一些优化(例如合并空闲内存块什么的),并且假设Heap 中没有扫描到的区域都是空闲的,统统refresh(实际上是把Stack中丢失了对象地址的无用对象清除了),这就是垃圾收集的过程;关于垃圾收集的更深入讲解请参考51CTO之前的文章《JVM内存模型及垃圾收集策略解析》。
JVM的体系结构
我们首先要搞清楚的是什么是数据以及什么是指令。然后要搞清楚对象的方法和对象的属性分别保存在哪里。
1)方法本身是指令的操作码部分,保存在Stack中;
2)方法内部变量作为指令的操作数部分,跟在指令的操作码之后,保存在Stack中(实际上是简单类型保存在Stack中,对象类型在Stack中保存地址,在Heap 中保存值);上述的指令操作码和指令操作数构成了完整的Java 指令。
3)对象实例包括其属性值作为数据,保存在数据区Heap 中。
非静态的对象属性作为对象实例的一部分保存在Heap 中,而对象实例必须通过Stack中保存的地址指针才能访问到。因此能否访问到对象实例以及它的非静态属性值完全取决于能否获得对象实例在Stack中的地址指针。
非静态方法和静态方法的区别:
非静态方法有一个和静态方法很重大的不同:非静态方法有一个隐含的传入参数,该参数是JVM给它的,和我们怎么写代码无关,这个隐含的参数就是对象实例在Stack中的地址指针。因此非静态方法(在Stack中的指令代码)总是可以找到自己的专用数据(在Heap 中的对象属性值)。当然非静态方法也必须获得该隐含参数,因此非静态方法在调用前,必须先new一个对象实例,获得Stack中的地址指针,否则JVM将无法将隐含参数传给非静态方法。
静态方法无此隐含参数,因此也不需要new对象,只要class文件被ClassLoader load进入JVM的Stack,该静态方法即可被调用。当然此时静态方法是存取不到Heap 中的对象属性的。
总结一下该过程:当一个class文件被ClassLoader load进入JVM后,方法指令保存在Stack中,此时Heap 区没有数据。然后程序技术器开始执行指令,如果是静态方法,直接依次执行指令代码,当然此时指令代码是不能访问Heap 数据区的;如果是非静态方法,由于隐含参数没有值,会报错。因此在非静态方法执行前,要先new对象,在Heap 中分配数据,并把Stack中的地址指针交给非静态方法,这样程序技术器依次执行指令,而指令代码此时能够访问到Heap 数据区了。
静态属性和动态属性:
前面提到对象实例以及动态属性都是保存在Heap 中的,而Heap 必须通过Stack中的地址指针才能够被指令(类的方法)访问到。因此可以推断出:静态属性是保存在Stack中的,而不同于动态属性保存在Heap 中。正因为都是在Stack中,而Stack中指令和数据都是定长的,因此很容易算出偏移量,也因此不管什么指令(类的方法),都可以访问到类的静态属性。也正因为静态属性被保存在Stack中,所以具有了全局属性。
在JVM中,静态属性保存在Stack指令内存区,动态属性保存在Heap数据内存区。
分享一篇文章具体出处不详
相关推荐
在JVM中,另有一个GC进程,定期扫描Heap,它根据Stack中保存的4字节对象地址扫描Heap,定位Heap中的对象,进行一些优化(例如合并空闲内存块什么的),并且假设Heap中的没有扫描到的区域都是空闲的,统统refresh...
在JVM中另有一个GC进程,定期扫描Heap,它根据Stack中保存的4字节对象地址扫描Heap,定位Heap中的对象,进行一些优化(例如合并空闲内存块什么的),并且假设Heap中的没有扫描到的区域都是空闲的,统统refresh(实际...
Stack Frame,非基本类型的对象在 JVM 栈上仅存放一个指向堆上的地址,因此 Java 中基本类型的变量是值传递,而非基本类型的变量是引用传递,Sun JDK 的实现中 JVM 栈的空间是在物理内存上分配的,而不是从堆上分配...
JVM的内存管理主要分为堆(Heap)、栈(Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)四个部分。堆用于存放对象实例,是垃圾回收的主要区域。栈负责存储局部变量和方法调用的状态,每个线程...
1. **堆(Heap)**:这是Java对象的主要存储区域,分为年轻代(Young Generation)和老年代(Tenured Generation)。年轻代又细分为Eden区、Survivor区(S0和S1),新生的对象主要在Eden区分配,经过几次垃圾收集后...
Java内存主要分为五个区域:堆(Heap)、栈(Stack)、方法区(Method Area)、程序计数器(PC Register)和本地方法栈(Native Method Stack)。 1. 堆(Heap):这是Java对象的主要存储区域,所有通过new创建的...
1. 堆(Heap):所有通过 new 创建的对象的内存都在堆中分配。 2. 栈(Stack):存放方法的局部变量和参数。 3. 本地方法栈(Native Method Stack):存放 native 方法的参数和返回值。 4. 方法区(Method Area):...
通过这种方式,JVM 能够高效地管理和执行 Java 程序中的方法调用。 ##### 2.4 JVM 的内存分配 内存分配是 JVM 运行过程中至关重要的环节。对于 Java 程序来说,大部分的对象都存储在堆(Heap)中。堆是 JVM 管理的...
在Java中,内存主要分为两个区域:栈(Stack)和堆(Heap),以及垃圾回收机制(Garbage Collection)。 栈是程序执行过程中的临时数据存储区域,主要用于存储基本类型(如int、char)和对象的引用。每当一个方法被...
2. **内存模型**:JVM的内存分为堆内存(Heap)、栈内存(Stack)、方法区(Method Area)、程序计数器(PC Register)和本地方法栈(Native Method Stack)。书中会详细解析各区域的功能、分配规则以及它们之间的...
这部分在JVM规范中被称为“非堆”(Non-Heap),在Java 8及以后版本,这部分被合并到堆内存中,称为元空间(Metaspace)。 - **本地方法栈(Native Method Stack)**:与JVM栈类似,但服务于本地方法(如C++方法)...
1. **堆内存(Heap)**:这是JVM管理的最大块内存区域,用于存储所有对象实例以及数组。堆内存又分为年轻代(Young Generation)和老年代(Old Generation),年轻代进一步细分为Eden区和两个Survivor区(S0、S1)。 2. **...
主要包括方法区(Method Area)、堆(Heap)、Java栈(Java Stack)、本地方法栈(Native Method Stack)、程序计数器(Program Counter)五个部分。 4. 垃圾回收机制:JVM中的垃圾回收主要是针对堆区进行的。垃圾...
在Java编程语言中,了解和控制JVM(Java虚拟机)的内存管理是至关重要的,尤其是在性能调优、资源管理和避免内存泄漏等方面。本文将深入探讨如何在Java中获取JVM内存大小,包括堆内存的总量、最大值以及剩余空间,并...
Java虚拟机(JVM)内存管理和垃圾回收是Java编程中至关重要的概念,它们直接影响着程序的性能和稳定性。本文将详细解析JVM内存结构以及垃圾回收机制。 首先,JVM内存主要分为四个区域: 1. **堆(Heap)**:这是...
JVM内存分为几个关键区域:方法区(Method Area)、堆(Heap)、栈(Stack)、程序计数器(PC Register)和本地方法栈(Native Method Stack)。每个区域都有特定的用途: - **方法区**:存储类信息、常量、静态...
Java程序运行在JVM上,JVM将内存划分为几个区域,包括堆内存(Heap)、栈内存(Stack)、方法区(Method Area)、程序计数器(PC Register)和本地方法栈(Native Method Stack)。其中,堆内存是所有线程共享的一块...
在一些平台上,在有些情况下,javacore也被称为javadump,它包含jvm和应用程序相关的在特定时刻的一些诊断信息,如操作系统,应用程序环境,线程,native stack本地堆,锁,和内存的信息。在生成heapdump文件的时候...
1. **堆内存(Heap)**:这是JVM中最大的一块内存区域,主要用于存储对象实例。堆被进一步划分为新生代(Young Generation)和老年代(Tenured/Old Generation),新生代又包括Eden区和两个Survivor区(From、To)。...