`
endual
  • 浏览: 3558587 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JVM 数据存储与逻辑

    博客分类:
  • jvm
 
阅读更多

    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异常。常见的出现这个异常的是无法返回的递归,因为此时栈中保存的信息都是方法返回的记录点。

 

分享到:
评论

相关推荐

    JVM高级特性与最佳实践(第2版)+pdf+源码

    2. **类加载机制**:JVM通过类加载器将.class文件加载到内存中,形成运行时数据区的类元数据。了解类加载过程(加载、验证、准备、解析、初始化)和双亲委派模型,有助于定制类加载逻辑和实现热部署。 3. **内存...

    JVM高级特性与最佳实践2.0 kindle版本

    《JVM高级特性与最佳实践2.0》是关于Java虚拟机(JVM)的一本深入解析书籍,主要面向对Java性能优化、JVM内部机制感兴趣的开发者和运维人员。本书内容丰富,涵盖了JVM的各个方面,包括内存管理、类加载机制、垃圾...

    jvm 启动过程 JVM 原理

    JVM由多个组件构成,包括类加载器、运行时数据区、执行引擎、本地方法接口和本地库。 JVM的启动过程可以分为以下几个关键步骤: 1. **加载**:当Java应用程序启动时,JVM首先通过类加载器加载主类(即包含main方法...

    JVM调优.pdf

    #### 二、JVM数据类型与存储机制 在深入讨论JVM调优之前,我们首先需要了解JVM中数据类型的分类及其存储机制。 ##### 1. 数据类型 Java虚拟机中的数据类型主要分为两类:基本类型和引用类型。 - **基本类型**:...

    JVM 全方位详细理解实战

    - **堆** 主要存储对象,是所有线程共享的区域,用于数据存储。对象的分配和回收都在堆中进行。 垃圾回收是JVM自动管理内存的重要机制,主要有以下几种策略: 1. **引用计数**:简单易懂,但无法处理循环引用。 2....

    JVM 原理及工作机制

    - **寄存器**:JVM使用一组逻辑上的寄存器进行运算,这些寄存器并不对应物理CPU的寄存器,而是为了解析字节码和执行指令。 - **栈**:每个线程都有自己的操作栈,用于存储局部变量和运算过程中的数据。 - **垃圾...

    Jvm入门必备手册

    - **特点**:尽管被描述为堆的一个逻辑部分,但由于存储的数据类型不同,通常被称为“非堆”。 - **作用**:存储类的信息,包括类的定义、常量池、字段和方法数据等。 - **生命周期**:方法区的生命周期与 Java 应用...

    JVM原理讲解和调优,详细讲解JVM底层

    此外,JVM还支持自定义类加载器,以便于实现特定的加载逻辑。 Java代码的编译和执行涉及从源代码到字节码的转换,再到JVM执行引擎解释执行字节码的过程。Java源码编译机制包括三个主要步骤:分析和输入到符号表、...

    深入jvm 内核-原理,诊断于优化视频教程

    ### 深入JVM内核:原理、诊断与优化 #### 一、JVM基础知识 **1.1 JVM概念** Java虚拟机(Java Virtual Machine,简称JVM)是一种用于执行Java字节码的虚拟机。它为Java程序提供了一个运行环境,能够独立于硬件平台...

    jvm的基本原理及结构

    #### 一、Java虚拟机(JVM)的逻辑与物理结构 JVM,即Java Virtual Machine,是运行Java字节码的虚拟机环境,它的设计目的是为了提供一个独立于硬件的运行环境,使得Java程序可以在任何安装了JVM的平台上运行。JVM的...

    JVM指令手册_jvm指令手册_

    5. **对象创建与访问指令**:`new`用于创建一个新的对象实例,`aload`和`astore`用于对象引用的加载和存储,`getfield`和`putfield`用于读写对象字段,`invokevirtual`、`invokespecial`、`invokestatic`、`invoke...

    jVM学习笔记.ppt

    逻辑结构主要包括Java源码编译器、JVM执行引擎、类加载器等组件,而物理结构则涵盖了堆、栈、本地方法栈、方法区等内存区域。JDK与JRE的区别在于,JDK包含了开发工具和JRE,而JRE仅包含运行时环境。 Java代码的编译...

    JVM指令集.zip

    - **数据操作指令**:包括加载(如`iload`、`fload`用于加载局部变量表中的整型和浮点型数据)、存储(如`istore`、`fstore`用于存储数据回局部变量表)、算术运算(如`iadd`、`imul`执行加法和乘法)和类型转换...

    JVM思维导图(包含所有JVM知识)

    - **对象创建与内存分配**:JVM根据对象大小和生命周期将其分配到堆内存的不同区域。小对象通常在Eden区创建,大对象直接进入老年代。对象的大小包括对象头、实例数据和对齐填充。 - **指针压缩**:在64位JVM中,-...

    jvm课程ppt

    双亲委派模型是JVM默认的类加载方式,通过自定义类加载器可以实现特定的加载逻辑。 三、运行时数据区 JVM内存分为堆、方法区、虚拟机栈、本地方法栈和程序计数器五个区域。其中,堆是所有线程共享的内存区域,用于...

    JVM知识点汇总

    但在jdk1.8中,方法区已经不存在,其存储的类信息、编译后的代码数据等已经移动到了元空间中。元空间并不在虚拟机中,而是直接占用的本地内存。 2. 堆内存 堆内存主要用于存放对象和数组,是JVM管理的内存中最大的...

    JVM高级特性与最佳实践

    方法区则保存类的信息,如类的元数据。程序计数器记录每个线程的执行位置。 其次,JVM的类加载机制是另一个重点。书中可能会讲解如何加载、链接和初始化类的过程,以及双亲委派模型,它是如何保证类加载的唯一性,...

    JVM调优总结.pdf

    这种分离有几个优点:使得处理逻辑和数据存储分离清晰,允许数据在多个栈之间共享,限制了栈的大小以避免栈溢出,同时允许堆动态扩展以适应不断变化的内存需求。 文档还讨论了基本垃圾回收算法和分代垃圾回收机制。...

    JVM内存配置优化

    1. **堆内存(Heap)**:主要用于存储对象实例、数组等引用类型的数据。在Java中使用`new`关键字创建的对象都将被存储在此处。 2. **栈内存(Stack)**:用于存储局部变量,如方法参数等。 3. **持久区(Permanent ...

Global site tag (gtag.js) - Google Analytics