类和对象运行时在内存里是怎么样的?各种变量、方法在运行时是怎么交互的?

转载自   类和对象运行时在内存里是怎么样的?各种变量、方法在运行时是怎么交互的?

在回答这个问题之前先了解一下Java的一些基础知识。


我们知道Java程序运行在虚拟机环境里,那我们先看一下虚拟机的大致内存结构。如下图所示,虚线框为整个虚拟机内存区域,其中有颜色的区域为Java程序所占的内存区域。




图中可见Java程序所占的内存区域可划分成5个部分:程序计数器、虚拟机栈(线程栈)、本地方法栈、堆(heap)和方法区(内含常量池)。其中方法区和堆由所有线程共享。


这5个区域作用和功能分别如下:


一、程序计数器:

它类似CPU寄存器中的PC寄存器,用于存放指令地址。因为Java虚拟机是多线程的,所以每一个线程都有一个独立的程序计数器结构,它与线程共存亡。不过Java虚拟机中的程序计数器指向的是正在执行的字节码地址,而CPU的PC寄存器指向的是下一条指令的地址。当线程去执行Native方法时,程序计数器则为Undefined。


二、虚拟机栈(线程栈):

一个线程一个栈,并且生命周期与线程相同。它内部由一个个栈帧构成,一个栈帧代表一个调用的方法,线程在每次方法调用执行时创建一个栈帧然后压栈,栈帧用于存放局部变量、操作数、动态链接、方法出口等信息。方法执行完成后对应的栈帧出栈。我们平时说的栈内存就是指这个栈。


一个线程中的方法可能还会调用其他方法,这样就会构成方法调用链,而且这个链可能会很长,而且每个线程都有方法处于执行状态。对于执行引擎来说,只有活动线程栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),这个栈帧关联的方法称为当前方法(Current Method)。


栈帧的大致结构如下图所示:





每一个栈帧的结构都包括了局部变量表、操作数栈、方法返回地址和一些额外的附加信息。某个方法的栈帧需要多大的局部变量表、多深的操作数栈都在编译程序时完全确定了,并且写入到类方法表的相应属性中了,因此某个方法的栈帧需要分配多少内存,不会受到程序运行期变量数据变化的影响,而仅仅取决于具体虚拟机的实现。


栈帧结构各部分功能:


1)局部变量区域:存储方法的局部变量和参数,存储单位以slot(4 byte)为最小单位。局部变量存放的数据类型有:基本数据类型、对象引用和return address(指向一条字节码指令的地址)。其中64位长度的long和double类型的变量会占用2个slot,其它数据类型只占用1个slot。


类的静态方法和对象的实例方法被调用时,各自栈帧对应的局部变量结构基本类似。但有以下如图示区别:实例方法中第一个位置存放的是它所属对象的引用。而静态方法则没有对象的引用。另外静态方法里所操作的静态变量存放在方法区。


void test(Object object){

    int i=0;

    Boolean b = false;

}

static void test1(int i, Object object, boolean b){

    ...

}



关于局部变量,还有一点需要强调,就是局部变量不像类的实例变量那样会有默认初始化值。所以局部变量需要手工初始化,如果一个局部变量定义了但没有赋初始值是不能使用的。


2)操作数栈 所谓操作数是指那些被指令操作的数据。当需要对参数操作时如c=a+b,就将即将被操作的参数数据压栈,如将a和b压栈,然后由操作指令将它们弹出,并执行操作。虚拟机将操作数栈作为工作区。Java虚拟机没有寄存器,所有参数传递、值返回都是使用操作数栈来完成的。


Java虚拟机的解释执行引擎称为“基于栈的执行引擎”,其中所指的“栈”就是操作数栈。


例如下面这段代码:


public static int add(int a,int b){

    int c=0;

    c=a+b;

    return c;

}

add(25,23);


主要步骤如图:




压栈的步骤如下:


0:  ....

1:   iload_0  // 把局部变量0压栈,int a;

2:   iload_1 // 局部变量1压栈,int b;

3:   iadd      //弹出2个变量,求和,结果压栈48

4:   istore_2 //弹出结果,放于局部变量2;int c;

5: ...


3)动态连接,它是个指向运行时常量池中该栈帧所属方法的引用。这个引用是为了支持方法调用过程中能进行动态连接。我们知道Class文件的常量池存有方法的符号引用,字节码中的方法调用指令就以指向常量池中方法的符号引用为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化称为静态解析。余下部分将在每一次运行期间转化为直接引用,这部分称为动态连接。


4)方法返回地址

正常退出,执行引擎遇到方法返回的字节码,将返回值传递给调用者。


异常退出,遇到Exception, 并且方法未捕捉异常,返回地址由异常处理器来确定,并且不会有任何返回值。


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


5)额外附加信息,虚拟机规范没有明确规定,由具体虚拟机实现。


Java虚拟机规范规定该区域有两种异常:


StackOverFlowError:当线程请求栈深度超出虚拟机栈所允许的深度时抛出


OutOfMemoryError:当Java虚拟机动态扩展到无法申请足够内存时抛出


另外需要提醒一下,在规范模型中,栈帧相互之间是完全独立的。但在大多数虚拟机的实现里都会做一些优化处理,这样两个栈帧可能会出现一部分重叠。这样在下面的栈帧会有部分操作数栈与上面栈帧的部分局部变量表重叠在一起,这样在进行方法调用时就可以有部分数据共享,而无须进行额外的参数复制传递了。具体情形如下图所示:




三、本地方法栈

Java可以通过java本地接口JNI(Java Native Interface)来调用其它语言编写(如C)的程序,在Java里面用native修饰符来描述一个方法是本地方法。本地方法栈就是虚拟机线程调用Native方法执行时的栈,它与虚拟机栈发挥类似的作用。但是要注意,虚拟机规范中没有对本地方法栈作强制规定,虚拟机可以自由实现,所以可以不是字节码。如果是以字节码实现的话,虚拟机栈本地方法栈就可以合二为一,事实上,OpenJDK和SunJDK所自带的HotSpot虚拟机就是直接将虚拟机栈和本地方法栈合二为一的。


Java虚拟机规范规定该区域也可抛出StackOverFlowError和OutOfMemoryError。


四、堆(heap)

这个区域用来放置所有对象实例以及数组。不过在JIT(Just-in-time)情况下有些时候也有可能在栈上分配对象实例。堆也是java垃圾收集器管理的主要区域(所以很多时候会称它为GC堆)。


从GC回收的角度看,由于现在GC基本都是采用的分代收集算法,所以堆内存结构还可以分块成:新生代和老年代;再细一点的有Eden空间、From Survivor空间、To Survivor空间等。如下图:




五、方法区

它是虚拟机在加载类文件时,用于存放加载过的类信息,常量,静态变量,及jit编译后的代码(类方法)等数据的内存区域。它是线程共享的。


方法区存放的信息包括:


类的基本信息:

  • 每个类的全限定名

  • 每个类的直接超类的全限定名(可约束类型转换)

  • 该类是类还是接口

  • 该类型的访问修饰符

  • 直接超接口的全限定名的有序列表


已装载类的详细信息:

  • 运行时常量池:

类信息除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量、符号引用,文字字符串、final变量值、类名和方法名常量,这部分内容将在类加载后存放到方法区的运行时常量池中。它们以数组形式访问,是调用方法、与类联系及类的对象化的桥梁。


这里再讲一下,JDK1.7之前运行时常量池是方法区的一部分,JDK1.7及之后版本已经将运行时常量池从方法区中移了出来,在堆(Heap)中开辟了一块区域存放运行时常量池。


运行时常量池除了存放编译期产生的Class文件的常量外,还可存放在程序运行期间生成的新常量,比较常见增加新常量方法有String类的internd()方法。String.intern()是一个Native方法,它的作用是:如果运行时常量池中已经包含一个等于此String对象内容的字符串,则返回常量池中该字符串的引用;如果没有,则在常量池中创建与此String内容相同的字符串,并返回常量池中创建的字符串的引用。不过JDK7的intern()方法的实现有所不同,当常量池中没有该字符串时,不再是在常量池中创建与此String内容相同的字符串,而改为在常量池中记录堆中首次出现的该字符串的引用,并返回该引用。


  • 字段信息:

字段信息存放类中声明的每一个字段(实例变量)的信息,包括字段的名、类型、修饰符。


如private String a = ""; 则a为字段名,String为描述符,private为修饰符。


  • 方法信息:

类中声明的每一个方法的信息,包括方法名、返回值类型、参数类型、修饰符、异常、方法的字节码。(在编译的时候,就已经将方法的局部变量表、操作数栈大小等完全确定并存放在字节码中,在加载载的时候,随着类一起装入方法区。)


在运行时,虚拟机线程调用方法时从常量池中获得符号引用,然后在运行时解析成方法的实际地址,最后通过常量池中的全限定名、方法和字段描述符,把当前类或接口中的代码与其它类或接口中的代码联系起来。


  • 静态变量:

就是类变量,被类的所有实例对象共享,我们只需知道,在方法区有个静态区,静态区专门存放静态变量和静态块。


  • 到类ClassLoader的引用:

到该类的类装载器的引用。


  • 到类Class的引用:

虚拟机为每一个被装载的类型创建一个Class实例,用来代表这个被装载的类。


Java虚拟机规范规定该区域可抛出OutOfMemoryError。


六、直接内存

直接内存(Direct Memory)虽然不是程序运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但这部分内存也被频繁使用,而且它也可能导致OutOfMemoryError异常出现。


在JDK1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native方法库直接分配堆外内存,然后通过一个存储在Java堆里面的DirecByteBuffer对象作为这块内存的引用进行操作。这样能在某些应用场景中显著提高性能,因为它避免了在Java堆和Native堆中来回复制数据。


显然,本机直接内存的分配不会受到Java堆大小的限制,但是,还是会受到本机总内存(包括RAM及SWAP区或者分页文件)的大小及处理器寻址空间的限制,从而导致动态扩展时出现OutOfMemoryError异常。


七、执行引擎

将字节码即时编译 优化 为本地代码, 然后执行。


在了解完这些知识以后,就可以知道:类和对象在运行时的内存里是怎么样的,以及各类型变量、方法在运行时是怎么交互的。


在程序运行时类是在方法区,实例对象本身在堆里面。


方法字节码在方法区。线程调用方法执行时创建栈帧并压栈,方法的参数和局部变量在栈帧的局部变量表。


对象的实例变量和对象一起在堆里,所以各个线程都可以共享访问对象的实例变量。


静态变量在方法区,所有对象共享。字符串常量等常量在运行时常量池。

各线程调用的方法,通过堆内的对象,方法区的静态数据,可以共享交互信息。


各线程调用的方法所有参数传递、方法返回值的返回,都是使用栈帧里的操作数栈来完成的。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328175.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java通过commons-fileupload实现多张图片的上传(jsp页面)

<div id"middle"><div id"form"><form action"ProductInfoServlet?tagadd" method"post" enctype"multipart/form-data" ><h2>三只松鼠--新增</h2><table align"center">&l…

系统架构师7

2017年11月11日 软件系统架构师考试经验分享 置顶 2017年11月13日 15:25:53 凌飞安 阅读数 7812 版权声明&#xff1a;原创作品&#xff0c;转载请注明出处&#xff01;个人主页 http://www.lingfeian.com https://blog.csdn.net/lingfeian/article/details/78520808 系统架构…

工业利用计算机实现生产自动化属于,自动化考试试题(含答案)

第一类&#xff1a;填空题一&#xff0e;填空题1&#xff0e;自动化控制系统按被控量的时间特性分为(连续量)和(离散量)。2&#xff0e;PLC 全称为(可编程序逻辑控制器)&#xff0c;DCS全称为( 集散控制系统)。3&#xff0e;输入输出单元是(PLC)与工业过程控制现场之间的连接部…

保定有国家承认的计算机学校吗,河北省122所大学名单,不在名单内的都是国家不承认的野鸡学校...

原标题&#xff1a;河北省122所大学名单&#xff0c;不在名单内的都是国家不承认的野鸡学校据教育部官网信息显示&#xff0c;截至2019年6月15日&#xff0c;河北省共有普通高等学校122所&#xff0c;其中本科院校61所&#xff0c;专科院校61所。在名单中虽然有一所211院校&…

从Java类到对象的创建过程都做了些啥?内存中的对象是啥样的?

转载自 从Java类到对象的创建过程都做了些啥&#xff1f;内存中的对象是啥样的&#xff1f;先回顾一下Java程序执行的过程&#xff1a;Java程序执行时&#xff0c;第一步系统创建虚拟机进程&#xff0c;然后虚拟器用类加载器Class Loader加载java程序类文件到方法区。方法区放…

ASP.NET Core MVC TagHelper实践HighchartsNET快速图表控件

ASP.NET Core MVC TagHelper最佳实践HighchartsNET快速图表控件支持ASP.NET Core。 曾经在WebForms上写过 HighchartsNET快速图表控件-开源 Highcharts的ASP.NET Web自定义控件。 今天我就来改造它&#xff0c;将其使用最新的TagHelper 来实践&#xff0c;学习TagHelper 的使用…

架构师6

系统架构师考试总结 2019年06月11日 10:48:47 devillyd2018 阅读数 103 2011年11月12日&#xff0c;在这个百年一遇的大单身节的第二天&#xff0c;我怀着无比紧张的心情走进了系统架构师的考场。 虽然暂时还不知道我的成绩&#xff0c;无所谓啦&#xff0c;虽然答的一般&…

计算机视觉论文doc,嘉炬-计算机视觉论文资料.doc

成 绩评卷人姓 名嘉炬学 号华 中 师 范 大 学研 究 生 课 程 论 文论文题目 计算机视觉技术在教育领域的应用完成时间 2015年1月15日课程名称 计算机视觉专 业 通信与信息系统年 级 2014级注&#xff1a;研究生须在规定期限内完成课程论文&#xff0c;并用A4页面打印&#xff0…

Oracle数据库基本概念理解(1)

--函数 数字转换为字符 --0 强制位数&#xff0c;9位数不够不显示 $美元 SELECT TO_CHAR(124.3456,0000.00) FROM dual ; SELECT TO_CHAR(124.3456,9999.99) FROM dual ; SELECT TO_CHAR(124.3456,$9999.99) FROM dual ; --日期 日期转换为字符 SELECT TO_CHAR(SYSDATE,YY…

关于Heap Dump

转载自 关于Heap DumpHeap Dump是什么&#xff1f; Heap Dump也叫堆转储文件&#xff0c;是一个Java进程在某个时间点上的内存快照。Heap Dump是有着多种类型的。不过总体上heap dump在触发快照的时候都保存了java对象和类的信息。通常在写heap dump文件前会触发一次FullGC&a…

使用StyleCop 进行代码评审

使用StyleCop对原代码进行审查&#xff0c;看编写的代码是否遵循设计规范、.Net约定和一些贯用法等。保证代码的一致性&#xff0c;可读性等等。 在此之前&#xff0c;先简单介绍下FxCop&#xff08;起初只是微软内部使用的工具&#xff09;,一个分析托管程序集&#xff0c;检测…

系统架构师5 ***********那就给个合格分了。111

https://download.csdn.net/download/sun_lq/11109495 https://download.csdn.net/download/u011669055/10736374 https://download.csdn.net/download/robertsoft/10747039 十年IT从业背景&#xff0c;一次考试通过系统分析师(通过系统分析师的学习 ... [复制链接] 发表于 …

2012三年大专计算机试题医学,计算机原理2012年4月真题(02384)

计算机原理2012年4月真题及答案解析(02384)计算机原理2012年4月真题及答案解析(02384)&#xff0c;该试卷为计算机原理自考历年真题试卷&#xff0c;包含答案及详细解析。一、单项选择题(本大题共15小题&#xff0c;每小题2分&#xff0c;共30分)在每小题列出的四个备选项中只有…

JVM内存管理------JAVA语言的内存管理概述

转载自 JVM内存管理------JAVA语言的内存管理概述引言 内存管理一直是JAVA语言自豪与骄傲的资本&#xff0c;它让JAVA程序员基本上可以彻底忽略与内存管理相关的细节&#xff0c;只专注于业务逻辑。不过世界上不存在十全十美的好事&#xff0c;在带来了便利的同时&#xf…

微软市值今天涨了 250 亿,这家离我们越来越远的公司,为什么生意反倒越来越好了?

纳德拉上台两年半&#xff0c;微软市值已经涨了 50% 今天早上&#xff0c;微软发布了今年第三季度的财报。受云计算和 Office 业务推动&#xff0c;财报后的盘后交易里&#xff0c;微软股价上涨 5.9%、市值涨了超过 250 亿美元——收购 LinkedIn 的钱差不多就回来了。 财报发布…

系统架构设计师考试 重要的部分

系统架构师考试比较的难&#xff0c;属于软件工程师考试中的高级考试&#xff0c;有选择题&#xff0c;分析题&#xff0c;论文&#xff0c;请坚持。 这是高产似母猪啊。 1.每天2小时&#xff0c;坚持了4年考过了软件设计师&#xff0c;系统架构师&#xff0c; 四年时间花了大…

计算机文化基础分析总结,《计算机文化基础实训》教学方案设计与课题分析总结.doc...

《计算机文化基础实训》教学方案设计与课题分析总结.doc《计算机文化基础一实训》教学方案设计与课题分析总结袁良风&#xff3b; 】我院自开展木课题研宄工作以来&#xff0c;紧紧围绕“项目教学法”教学的应 用问题&#xff0c;积极主动地开展专题研究和教改实验&#xff0c;…

Oracle数据库基本概念理解(2)

--删除用户 drop user sz cascade; --创建表空间 create tablespace worktablsp datafile C:\app\lenovo\oradata\orcl\EMPTB.dbf SIZE 5MAUTOEXTEND ON; --修改表空间 ALTER tablespace worktablsp ADD datafile C:\app\lenovo\oradata\orcl\EMPTB.dbf SIZE 5M;--扩展数据文件…

Java中关于String类型的10个问题

转载自 Java中关于String类型的10个问题1. 如何比较两个字符串&#xff1f;用“”还是equals 简单来说&#xff0c;“”是用来检测俩引用是不是指向内存中的同一个对象&#xff0c;而equals()方法则检测的是两个对象的值是否相等。只要你想检测俩字符串是不是相等的&#xff…

[ASP.NET Core] Static File Middleware

前言 本篇文章介绍ASP.NET Core里&#xff0c;用来处理静态档案的Middleware&#xff0c;为自己留个纪录也希望能帮助到有需要的开发人员。 ASP.NET Core官网 结构 一个Web站台最基本的功能&#xff0c;就是在接收到从「浏览器传入」的HTTP Request封包后&#xff0c;将站台内所…