Java虚拟机中,数据类型可以分为两类:基本类型和引用类型。基本类型的变量保存原始值,即:他代表的值就是数值本身;而引用类型的变量保存引用值。“引用值”代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置。
基本类型包括:byte, short, int, long, char, float, double, Boolean, returnAddress
引用类型包括:类类型,接口类型和数组。
堆与栈
堆和栈是程序运行的关键,很有必要把他们的关系说清楚。栈是运行时的单位,而堆是存储的单位。
栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿。
在Java中一个线程就会相应有一个线程栈与之对应,这点很容易理解,因为不同的线程执行逻辑有所不同,因此需要一个独立的线程栈。而堆则是所有线程共享
的。栈因为是运行单位,因此里面存储的信息都是跟当前线程(或程序)相关信息的。包括局部变量、程序运行状态、方法返回值等等;而堆只负责存储对象信息。
为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗?
第一
,从软件设计的角度看,栈代表了处理逻辑,而堆代表了数据。这样分开,使得处理逻辑更为清晰。分而治之的思想。这种隔离、模块化的思想在软件设计的方方面面都有体现。
第二
,堆与栈的分离,使得堆中的内容可以被多个栈共享(也可以理解为多个线程访问同一个对象)。这种共享的收益是很多的。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另一方面,堆中的共享常量和缓存可以被所有栈访问,节省了空间。
第三
,栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分。由于栈只能向上增长,因此就会限制住栈存储内容的能力。而堆不同,堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分,使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可。
第四
,面向对象就是堆和栈的完美结合。其实,面向对象方式的程序与以前结构化的程序在执行上没有任何
区别。但是,面向对象的引入,使得对待问题的思考方式发生了改变,而更接近于自然方式的思考。当我们把对象拆开,你会发现,对象的属性其实就是数据,存放
在堆中;而对象的行为(方法),就是运行逻辑,放在栈中。我们在编写对象的时候,其实即编写了数据结构,也编写的处理数据的逻辑。不得不承认,面向对象的
设计,确实很美。
在Java中,Main函数就是栈的起始点,也是程序的起始点。
程序要运行总是有一个起点的。同C语言一样,java中的Main就是那个起点。无论什么java程序,找到main就找到了程序执行的入口:)
堆中存什么?栈中存什么?
堆中存的是对象。栈中存的是基本数据类型和堆中对象的引用。一个对象的大小是不可估计的,或者说是可以动态变化的,但是在栈中,一个对象只对应了一个4btye的引用(堆栈分离的好处:))。
为什么不把基本类型放堆中呢?因为其占用的空间一般是1~8个字节——需要空间比较少,而且因为是基本类型,所以不会出现动态增长的情况——长度固定,因
此栈中存储就够了,如果把他存在堆中是没有什么意义的(还会浪费空间,后面说明)。可以这么说,基本类型和对象的引用都是存放在栈中,而且都是几个字节的
一个数,因此在程序运行时,他们的处理方式是统一的。但是基本类型、对象引用和对象本身就有所区别了,因为一个是栈中的数据一个是堆中的数据。最常见的一
个问题就是,Java中参数传递时的问题。
Java中的参数传递时传值呢?还是传引用?
要说明这个问题,先要明确两点:
1. 不要试图与C进行类比,Java中没有指针的概念
2. 程序运行永远都是在栈中进行的,因而参数传递时,只存在传递基本类型和对象引用的问题。不会直接传对象本身。
明确以上两点后。Java在方法调用传递参数时,因为没有指针,所以它都是进行传值调用(这点可以参考C的传值调用)。因此,很多书里面都说Java是进行传值调用,这点没有问题,而且也简化的C中复杂性。
但是传引用的错觉是如何造成的呢?在运行栈中,基本类型和引用的处理是一样的,都是传值,所以,如果是传引用的方法调用,也同时可以理解为“传引用值”的
传值调用,即引用的处理跟基本类型是完全一样的。但是当进入被调用方法时,被传递的这个引用的值,被程序解释(或者查找)到堆中的对象,这个时候才对应到
真正的对象。如果此时进行修改,修改的是引用对应的对象,而不是引用本身,即:修改的是堆中的数据。所以这个修改是可以保持的了。
对象,从某种意义上说,是由基本类型组成的。可以把一个对象看作为一棵树,对象的属性如果还是对象,则还是一颗树(即非叶子节点),基本类型则为树的叶子
节点。程序参数传递时,被传递的值本身都是不能进行修改的,但是,如果这个值是一个非叶子节点(即一个对象引用),则可以修改这个节点下面的所有内容。
堆和栈中,栈是程序运行最根本的东西。程序运行可以没有堆,但是不能没有栈。而堆是为栈进行数据存储服务,说白了堆就是一块共享的内存。不过,正是因为堆和栈的分离的思想,才使得Java的垃圾回收成为可能。
Java中,栈的大小通过-Xss来设置,当栈中存储数据比较多时,需要适当调大这个值,否则会出现java.lang.StackOverflowError异常。常见的出现这个异常的是无法返回的递归,因为此时栈中保存的信息都是方法返回的记录点。
分享到:
相关推荐
2. **类加载机制**:JVM通过类加载器将.class文件加载到内存中,形成运行时数据区的类元数据。了解类加载过程(加载、验证、准备、解析、初始化)和双亲委派模型,有助于定制类加载逻辑和实现热部署。 3. **内存...
《JVM高级特性与最佳实践2.0》是关于Java虚拟机(JVM)的一本深入解析书籍,主要面向对Java性能优化、JVM内部机制感兴趣的开发者和运维人员。本书内容丰富,涵盖了JVM的各个方面,包括内存管理、类加载机制、垃圾...
JVM由多个组件构成,包括类加载器、运行时数据区、执行引擎、本地方法接口和本地库。 JVM的启动过程可以分为以下几个关键步骤: 1. **加载**:当Java应用程序启动时,JVM首先通过类加载器加载主类(即包含main方法...
#### 二、JVM数据类型与存储机制 在深入讨论JVM调优之前,我们首先需要了解JVM中数据类型的分类及其存储机制。 ##### 1. 数据类型 Java虚拟机中的数据类型主要分为两类:基本类型和引用类型。 - **基本类型**:...
- **堆** 主要存储对象,是所有线程共享的区域,用于数据存储。对象的分配和回收都在堆中进行。 垃圾回收是JVM自动管理内存的重要机制,主要有以下几种策略: 1. **引用计数**:简单易懂,但无法处理循环引用。 2....
- **寄存器**:JVM使用一组逻辑上的寄存器进行运算,这些寄存器并不对应物理CPU的寄存器,而是为了解析字节码和执行指令。 - **栈**:每个线程都有自己的操作栈,用于存储局部变量和运算过程中的数据。 - **垃圾...
- **特点**:尽管被描述为堆的一个逻辑部分,但由于存储的数据类型不同,通常被称为“非堆”。 - **作用**:存储类的信息,包括类的定义、常量池、字段和方法数据等。 - **生命周期**:方法区的生命周期与 Java 应用...
此外,JVM还支持自定义类加载器,以便于实现特定的加载逻辑。 Java代码的编译和执行涉及从源代码到字节码的转换,再到JVM执行引擎解释执行字节码的过程。Java源码编译机制包括三个主要步骤:分析和输入到符号表、...
### 深入JVM内核:原理、诊断与优化 #### 一、JVM基础知识 **1.1 JVM概念** Java虚拟机(Java Virtual Machine,简称JVM)是一种用于执行Java字节码的虚拟机。它为Java程序提供了一个运行环境,能够独立于硬件平台...
#### 一、Java虚拟机(JVM)的逻辑与物理结构 JVM,即Java Virtual Machine,是运行Java字节码的虚拟机环境,它的设计目的是为了提供一个独立于硬件的运行环境,使得Java程序可以在任何安装了JVM的平台上运行。JVM的...
5. **对象创建与访问指令**:`new`用于创建一个新的对象实例,`aload`和`astore`用于对象引用的加载和存储,`getfield`和`putfield`用于读写对象字段,`invokevirtual`、`invokespecial`、`invokestatic`、`invoke...
逻辑结构主要包括Java源码编译器、JVM执行引擎、类加载器等组件,而物理结构则涵盖了堆、栈、本地方法栈、方法区等内存区域。JDK与JRE的区别在于,JDK包含了开发工具和JRE,而JRE仅包含运行时环境。 Java代码的编译...
- **数据操作指令**:包括加载(如`iload`、`fload`用于加载局部变量表中的整型和浮点型数据)、存储(如`istore`、`fstore`用于存储数据回局部变量表)、算术运算(如`iadd`、`imul`执行加法和乘法)和类型转换...
- **对象创建与内存分配**:JVM根据对象大小和生命周期将其分配到堆内存的不同区域。小对象通常在Eden区创建,大对象直接进入老年代。对象的大小包括对象头、实例数据和对齐填充。 - **指针压缩**:在64位JVM中,-...
双亲委派模型是JVM默认的类加载方式,通过自定义类加载器可以实现特定的加载逻辑。 三、运行时数据区 JVM内存分为堆、方法区、虚拟机栈、本地方法栈和程序计数器五个区域。其中,堆是所有线程共享的内存区域,用于...
但在jdk1.8中,方法区已经不存在,其存储的类信息、编译后的代码数据等已经移动到了元空间中。元空间并不在虚拟机中,而是直接占用的本地内存。 2. 堆内存 堆内存主要用于存放对象和数组,是JVM管理的内存中最大的...
方法区则保存类的信息,如类的元数据。程序计数器记录每个线程的执行位置。 其次,JVM的类加载机制是另一个重点。书中可能会讲解如何加载、链接和初始化类的过程,以及双亲委派模型,它是如何保证类加载的唯一性,...
这种分离有几个优点:使得处理逻辑和数据存储分离清晰,允许数据在多个栈之间共享,限制了栈的大小以避免栈溢出,同时允许堆动态扩展以适应不断变化的内存需求。 文档还讨论了基本垃圾回收算法和分代垃圾回收机制。...
1. **堆内存(Heap)**:主要用于存储对象实例、数组等引用类型的数据。在Java中使用`new`关键字创建的对象都将被存储在此处。 2. **栈内存(Stack)**:用于存储局部变量,如方法参数等。 3. **持久区(Permanent ...