| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> Java 类和对象在内存中的表现形式,栈、堆、方法区、常量池 -> 正文阅读 |
|
[Java知识库]Java 类和对象在内存中的表现形式,栈、堆、方法区、常量池 |
本文为joshua317原创文章,转载请注明:转载自joshua317博客?Java 类和对象在内存中的表现形式,栈、堆、方法区、常量池 - joshua317的博客 Java内存分配与管理是Java的核心技术之一,不管学习任何一门语言,我们要知其然,知其所以然,本文主要分析下Java中类和对象在内存中的表现形式,方便我们对其有更深了解。一般Java在内存分配时会涉及到这几个区域:栈区(stack)、堆区(heap)、方法区(Method Area)、常量池。我们先对下面几个概念进行深刻了解后,再进行画图分析类和对象在内存中的变化及表现形式。 栈:存放基本类型的数据和对象的引用变量的数据,但对象本身不存放在栈中,而是存放在堆中(new 出来的对象) 堆:存放用new产生的对象数据,每个对象包含了一个与之对应的 class 类的信息。 方法区(又称为静态区):存放对象中用static定义的静态成员 常量池:通常用来存放常量数据、静态变量、类的加载信息等 一、栈区在函数(方法)中定义的一些基本类型的变量或者对象的引用变量都在栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。 每个方法(Method)执行时,都会创建一个方法栈区,用于存储局部变量表、操作数栈、动态链接、方法出口信息等 栈中所存储的变量和引用都是局部的(即:定义在方法体中的变量或者引用),局部变量和引用都在栈中(包括final的局部变量) 八种基本数据类型(byte、short、int、long、float、double、char、boolean)的局部变量(定义在方法体中的基本数据类型的变量)在栈中存储的是它们对应的值 每个线程包含一个栈区,栈中只保存基本数据类型的变量和引用数据类型的变量,每个栈中的数据(基本数据类型和对象的引用)都是私有的,其它栈是无法进行访问的。栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。 栈中还存储局部的对象的引用(定义在方法体中的引用类型的变量),对象的引用并不是对象本身,而是对象在堆中的地址,换句话说,局部的对象的引用所指对象在堆中的地址在存储在了栈中。当然,如果对象的引用没有指向具体的对象,对象的引用则是 栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。 栈有一个很重要的特殊性,就是存在栈中的数据可以共享。 二、堆区堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 堆内存是被所有线程共享的一块内存区域,在虚拟机启动时创建。Java堆(Java Heap)唯一目的就是存放对象实例。所有的对象实例及数组都要在**Java堆(Java Heap)**上分配内存空间。 在堆中产生了一个数组或对象后,在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。引用变量就相当于是为数组或者对象起的一个名称。 引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉),这也是Java比较占内存的原因。 实际上,栈中的变量指向堆内存中的变量,这就是Java中的指针! Java的堆是一个运行时数据区,类的对象从中分配空间。对象一般通过new 来创建,例如 三、方法区方法区跟堆一样,又被称为静态区,通常存放常量数据。它存储已被Java虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等,它跟堆一样,被所有的线程共享。 3.1 存储的类信息对每个加载的类型(类class、接口interface、枚举enum、注解annotation),JVM必须在方法区中存储以下类型信息:
除此之外还方法区(Method Area)存储类信息还有
3.2 存储的常量static final修饰的成员变量都存储于 方法区(Method Area)中 3.3 存储的静态变量
3.4 存储的方法(Method)程序运行时会加载类编译生成的字节码,这个过程中静态变量(类变量)和静态方法及普通方法对应的字节码加载到方法区。 方法区中没有实例变量,这是因为,类加载先于对应类对象的产生,而实例变量是和对象关联在一起的,没有对象就不存在实例变量,类加载时没有对象,所以方法区中没有实例变量。 静态变量(类变量)和静态方法及普通方法在方法区(Method Area)存储方式是有区别的 四、常量池常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。 除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用,比如:类和接口的全限定名;字段的名称和描述符;方法和名称和描述符。 虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和floating point常量)和对其他类型,字段和方法的符号引用。对于String常量,它的值是在常量池中的。而JVM中的常量池在内存当中是以表的形式存在的,对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引用。说到这里,对常量池中的字符串值的存储位置应该有一个比较明了的理解了。在程序执行的时候,常量池会储存在方法区(Method Area),而不是堆中。 五、画图分析类实例化及操作时在内存中的变化及表现形式
Java Copy 上面这段代码首先有个主程序的类Main,这个我们不过多说明。我们主要分析main函数体里面的这段代码。 我们需要知道在Cat类中,定义了三个成员属性:name、age、weight;定义了一个成员方法:say();
在main() 函数里实例化对象 cat, 内存中在堆区内会给实例化对象 cat 分配一个内存地址,然后我们给对象 cat进行了赋值并且打印了一些信息,最后调用了成员方法 say() ,程序执行完毕。 1.在程序的执行过程中,首先Main类中的成员属性和成员方法会加载到方法区 2.程序执行类Main的main() 方法时,main()函数方法体会进入栈区,这一过程叫做进栈(压栈)。 3.程序执行到? 4.接下来对 cat 对象进行赋值
先在栈区找到引用变量cat,然后根据地址值找到 new Cat() 对象的内存地址,并对里面的属性进行赋值操作。由于成员属性name的类型为String,为引用数据类型,所以此时会在常量池开辟一块地址空间 5.当程序执行到? 6.在方法体 本文为joshua317原创文章,转载请注明:转载自joshua317博客?Java 类和对象在内存中的表现形式,栈、堆、方法区、常量池 - joshua317的博客 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 0:18:23- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |