序言

为什么有时候学着学着会突然之间觉得一切度是那么无趣,男的每个月也有那么几天难道?哈哈,不然是什么,我还是要坚持,可以做少一点,但是不能什么度不做。总会过去的,加油

--WZY

一、运行时数据区

什么叫运行时数据区呢,看下图就知道了,今天的重点就围绕这张图讲。

1、程序计数器(寄存器)

当前线程所执行的字节码行号指示器

字节码解释器工作依赖计数器控制完成

通过执行线程行号记录,让线程轮流切换各条线程之间计数器互不影响

线程私有,生命周期与线程相同,随JVM启动而生,JVM关闭而死

线程执行Java方法时,记录其正在执行的虚拟机字节码指令地址

线程执行Nativan方法时,计数器记录为空(Undefined)

唯一在Java虚拟机规范中没有规定任何OutOfMemoryError情况区域

在这其中,很多不理解的没关系,我们学过多线程,有两个线程,其中一个线程可以暂停使用,让其他线程运行,然后等自己获得cpu资源时,又能从暂停的地方开始运行,那么为什么能够记住暂停的位置的,这就依靠了程序计数器, 通过这个例子,大概了解一下程序计数器的功能。

2、本地方法栈

不知道大家看过源码没有,看过的都应该知道,很多的算法或者一个功能的实现,都被java封装到了本地方法中,程序直接通过调用本地的方法就行了,本地方法栈就是用来存放这种方法的,实现该功能的代码可能是C也可能是C++,反正不一定就是java实现的。

上面两个不是我们所要学习的重点,接下来三个才是重点。

3、虚拟机栈

这个大家都应该有所了解,现在来细讲它,虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用来存放存储局部变量表、操作数表、动态连接、方法出口等信息,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。    这个话怎么理解呢?比如执行一个类(类中有main方法)时,执行到main方法,就会把为main方法创建一个栈帧,然后在加到虚拟机栈中,栈帧中会存放这main方法中的各种局部变量,对象引用等东西。如图

当在main方法中调用别的方法时,就会有另一个方法的栈帧入虚拟机栈,当该方法调用完了之后,弹栈,然后main方法处于栈顶,就继续执行,直到结束,然后main方法栈帧也弹栈,程序就结束了。总之虚拟机栈中就是有很多个栈帧的入栈出栈,栈帧中存放的都市一些变量名等东西,所以我们平常说栈中存放的是一些局部变量,因为局部变量就是在方法中。也就是在栈帧中,就是这样说过来的。

以上说的三个都是线程不共享的,也就是这部分内存,每个线程独有,不会让别的线程访问到,接下来的两个就是线程共享了,也就会出现线程安全问题。

4、堆

所有线程共享的一块内存区域。Java虚拟机所管理的内存中最大的一块,因为该内存区域的唯一目的就是存放对象实例。几乎所有的对象实例度在这里分配内存,也就是通常我们说的new对象,该对象就会在堆中开辟一块内存来存放对象中的一些信息,比如属性呀什么的。同时堆也是垃圾收集器管理的主要区域。因此很多时候被称为"GC堆",虚拟机的垃圾回收机制等下一篇文章来讲解。 在上一点讲的栈中存放的局部引用变量所指向的大多数度会在堆中存放。

5、方法区和其中的运行时常量池

和堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、和编译器编译后的代码(也就是存储字节码文件。.class)等数据,这里可以看到常量也会在方法区中,是因为方法区中有一个运行时常量池,为什么叫运行时常量池,因为在编译后期生成的是各种字面量(字面量的意思就是值,比如int i=3,这个3就是字面量的意思)和符号引用,这些是存放在一个叫做常量池(这个常量池是在字节码文件中)的地方,当类加载进入方法区时,就会把该常量池中的内容放入运行时常量池中。这里要注意,运行时常量池和常量池,不要搞混淆了,字节码文件中也有常量池,在后面的章节会详细讲解这个东西。现在只需要知道方法区中有一个运行时常量池,就是用来存放常量的。还有一点,运行时常量池不一定就一定要从字节码常量池中拿取常量,可能在程序运行期间将新的常量放入池中,比如String.intern()方法,这个方法的作用就是:先从方法区的运行时常量池中查找看是否有该值,如果有,则返回该值的引用,如果没有,那么就会将该值加入运行时常量池中。

二、练习。画内存图。

平常分析中用到的最多还是堆、虚拟机栈和方法区。

例如:看下面这段程序,然后画出内存分析图

最主要是看我的分析过程,这个图由于要显示出动态弹栈画不了,所以只能够那样画一下了。

1、首先运行程序,Demo1_car.java就会变为Demo1_car.class,将Demo1_car.class加入方法区,检查是否字节码文件常量池中是否有常量值,如果有,那么就加入运行时常量池

2、遇到main方法,创建一个栈帧,入虚拟机栈,然后开始运行main方法中的程序

3、Car c1 = new Car(); 第一次遇到Car这个类,所以将Car.java编译为Car.class文件,然后加入方法区,跟第一步一样。然后new Car()。就在堆中创建一块区域,用于存放创建出来的实例对象,地址为0X001.其中有两个属性值 color和num。默认值是null 和 0

4、然后通过c1这个引用变量去设置color和num的值,

5、调用run方法,然后会创建一个栈帧,用来装run方法中的局部变量的,入虚拟机栈,run方法中就打印了一句话,结束之后,该栈帧出虚拟机栈。又只剩下main方法这个栈帧了

6、接着又创建了一个Car对象,所以又在堆中开辟了一块内存,之后就是跟之前的步骤一样了。

这样就分析结束了,在脑袋中就应该有一个大概的认识对堆、虚拟机栈、和方法区。注意这个方法区的名字,并不是就单单装方法的,能装很多东西。

这个只是一个简单的分析,可以再讲具体一点,1、创建对象,在堆中开辟内存时是如何分配内存的?2、对象引用是如何找到我们在堆中的对象实例的?通过这两个问题来加深我们的理解。

1、创建对象,在堆中开辟内存时是如何分配内存的?

两种方式:指针碰撞和空闲列表。我们具体使用的哪一种,就要看我们虚拟机中使用的是什么了。

指针碰撞:假设Java堆中内存是绝对规整的,所有用过的内存度放一边,空闲的内存放另一边,中间放着一个指针作为分界点的指示器,所分配内存就仅仅是把哪个指针向空闲空间那边挪动一段与对象大小相等的举例,这种分配方案就叫指针碰撞

空闲列表:有一个列表,其中记录中哪些内存块有用,在分配的时候从列表中找到一块足够大的空间划分给对象实例,然后更新列表中的记录。这就叫做空闲列表

2、对象引用是如何找到我们在堆中的对象实例的?

这个问题也可以称为对象的访问定位问题,也有两种方式。句柄访问和直接指针访问。 画两张图就明白了。

句柄访问:Java堆中会划分出一块内存来作为句柄池,引用变量中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息

解释图:在栈中有一个引用变量指向句柄池中一个句柄的地址,这个句柄又包含了两个地址,一个对象实例数据,一个是对象类型数据(这个在方法区中,因为类字节码文件就放在方法区中),

直接指针访问:引用变量中存储的就直接是对象地址了,如图所示

解释:在堆中就不会分句柄池了,直接指向了对象的地址,对象中包含了对象类型数据的地址。

区别:这两种各有各的优势,

使用句柄来访问的最大好处就是引用变量中存储的是稳定的句柄地址,对象被移动(在垃圾收集时移动对象是很普通的行为)时就会改变句柄中实力数据指针,但是引用变量所指向的地址不用改变。

而使用直接指针访问方式最大的好处就是速度更快,节省了一次指针定位的时间开销,但是在对象被移动时,又需要改变引用变量的地址。在我们上面分析的例子中,就是使用的直接指针访问的方式。

java虚拟机内存_java虚拟机内存区域的划分以及作用详解相关推荐

  1. java 永久代_Java新生代、老生代和永久代详解

    前言: 还是面试经常被q,小结一下 image.png JVM中的堆一般分为三部分,新生代.老年代和永久代. 1 新生代 主要是用来存放新生的对象.一般占据堆空间的1/3,由于频繁创建对象,所以新生代 ...

  2. java构造方法重载_Java 重载、重写、构造函数的实例详解

    Java 重载.重写.构造函数的实例详解 方法重写 1.重写只能出现在继承关系之中.当一个类继承它的父类方法时,都有机会重写该父类的方法.一个特例是父类的方法被标识为final.重写的主要优点是能够定 ...

  3. java 组合对象_Java 中组合模型之对象结构模式的详解

    Java 中组合模型之对象结构模式的详解 一.意图 将对象组合成树形结构以表示"部分-整体"的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 二.适用性 ...

  4. java jstack使用_JAVA语言之JVM 中jstack命令使用详解

    本文主要向大家介绍了JAVA语言之JVM 中jstack命令使用详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. Java程序问题定位时线程栈信息是一个重要线索,如下: " ...

  5. java example 去重_Java中mybatis关于example类的使用详解

    这几天刚接触example,很多内容都是破碎的,写一篇博文加深理解. 一.什么是example类 mybatis-generator会为每个字段产生如上的Criterion,如果表的字段比较多,产生的 ...

  6. java架构升级_java架构之路(多线程)synchronized详解以及锁的膨胀升级过程

    上几次博客,我们把volatile基本都说完了,剩下的还有我们的synchronized,还有我们的AQS,这次博客我来说一下synchronized的使用和原理. synchronized是jvm内 ...

  7. java运行时_java编译时与运行时概念与实例详解

    Java编译时与运行时很重要的概念,但是一直没有明晰,这次专门博客写明白概念. 基础概念 编译时 编译时顾名思义就是正在编译的时候.那啥叫编译呢?就是编译器帮你把源代码翻译成机器能识别的代码.(当然只 ...

  8. java运行原理_Java程序的加载与运行原理详解

    Java程序的运行包括两个非常重要的阶段: 一.编译阶段 第一步:程序员需要在计算机硬盘中任意位置创建一个.java扩展名的文件,该文件被称为 java源文件,源文件当中编写的是java源代码/源程序 ...

  9. java修饰方法_java接口中方法、属性修饰符详解

    java接口的修饰符:abstract(inteeface本身就是抽象的,加不加abstract都一样). 接口中字段的修饰符:public static final(默认不写) 如下解释: publ ...

  10. java封装数组_Java封装数组之动态数组实现方法详解

    本文实例讲述了Java封装数组之动态数组实现方法.分享给大家供大家参考,具体如下: 前言:在此之前,我们封装的数组属于静态数组,也即数组空间固定长度,对于固定长度的数组当元素超过容量时会报数组空间不足 ...

最新文章

  1. 官网的Ext direct包中.NET版的问题
  2. MATLAB加入螺旋相位板调制,平板式螺旋相位板的设计与应用
  3. conda如何升级pytorch_第一节 PyTorch简介及环境配置
  4. 计算机视觉图像去噪原理,AI笔记: 计算机视觉之图像滤波去噪: 原理、方法和效果比较...
  5. 使用MEAT在iOS设备上采集取证信息
  6. 传奇私服DBC2000合并数据库时删除重复Name关键字SQL指令
  7. caffe教程笔记《Solver》
  8. 粤语 之 粤语学习的一些学习网站和工具整理
  9. java中dao_java中的Dao类是什么意思?
  10. bamboo 启动报错,无法正常访问
  11. UVM中 sequence中的starting_phase
  12. ih5语言叫html5,iH5最专业的H5制作工具
  13. BFD1从北京顺义新国展到酒仙桥特斯拉办公室
  14. ARM-ADC模数转换
  15. 数学四大思想八大方法_中考数学专题五,四种数学思想方法,第3个比较难掌握...
  16. 文件IOday02--------时间编程与文件IO
  17. 记一次蚂蚁金服的面试经历
  18. 科学道德与学风-2021雨课堂答案-第6章
  19. ios android 同步的备忘录,iOS 备忘录如何共享给好友编辑 / Android 如何实现下拉搜索 | 有轻功 #012...
  20. Java swing皮肤(look and feel)大全

热门文章

  1. 直播防盗链,域名设置
  2. 【321天】跃迁之路——程序员高效学习方法论探索系列(实验阶段79-2017.12.23)...
  3. [安卓历险记] Error when loading the SDK
  4. windows下怎么样搭建RobotFramework测试环境
  5. Windows和Linux DNS Cache清理
  6. 软件开发过程中最重要的是人?还是领导者?
  7. 微信小程序的模块化开发,提高效率第一篇
  8. 记录一次Jdk1.8中stream流的问题排查
  9. 「精品推荐」FEBS-Shiro 2.0,一款好用美观的权限管理系统
  10. 微服务架构实战篇(六):Spring boot2.x 集成阿里大鱼短信接口详解与Demo