前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >虚拟机的前世今生和Java内存区域 顶

虚拟机的前世今生和Java内存区域 顶

作者头像
须臾之余
发布2020-07-21 10:20:45
4060
发布2020-07-21 10:20:45
举报
文章被收录于专栏:须臾之余

Java程序执行过程

javac编译成.class文件,然后jvm将其加载到方法区,执行引擎将会执行这些字节码,执行时会翻译成操作系统相关函数,jvm作为.class文件的翻译存在,输入字节码,调用操作系统函数。 过程如下:Java文件->编译器->字节码->jvm->机器码。

JVM、JRE、JDK的关系

JVM充当翻译的角色,把class翻译成机器识别的代码。 JRE包含jvm,还提供很多类库(也就是jar包,比如读取或者操作文件,连接网络,使用IO等)JVM标准加上实现的一大堆基础类库,组成java运行时环境。 JDK:负责编译代码,调试代码,打包代码,有时候还需要反编译代码,jdk提供了一些非常nice的工具,比如javac(编译代码),java -jar打包代码,javap反汇编等 JVM的作用是:从软件层面屏蔽不同操作系统在底层硬件和指令的不同。 同时JVM是一个虚拟化的操作系统,类似Linux或者Windos的操作系统,只是它架在操作系统上,接收字节码也就是class,把字节码翻译成操作系统上的机器码进行执行。

JVM的发展

常见的Hotspot虚拟机,Jrocket,J9,TaobaoVM等

JVM整体知识模块

JVM能涉及非常庞大的一块知识体系,比如内存结构、垃圾回收、类加载、性能调优、JVM自身优化技术、执行引擎、类文件结构、监控工具等。 但是所有的知识体系这,都和内存结构有一定的联系: 比如垃圾回收就是内存、类加载加载到的地方也是内存、性能优化也涉及到内存优化、执行引擎与内存密不可分、类文件结构与内存设计有关系、监控工具也会监控内存,所以内存结构处于JVM中核心位置,也是属于我们入门JVM学习的最好的选择。 同时JVM是一个虚拟化的操作系统,所以除了要虚拟化指令之外,最重要的一个事情就是需要虚拟化内存,这个虚拟化内存就是JVM的内存区域。

JVM的内存区域

运行时数据区域

在JVM中,JVM内存主要分为堆、程序计数器、方法区、虚拟机栈和本地方法栈等 按照与现场的关系划分为: 线程私有区域、线程共享区域 直接内存:没有被虚拟化的操作系统上的其它内存(比如操作系统上有8G内存,被JVM虚拟化了3G,那么还剩5G,JVM是借助一些工具使用这5G内存的,这部分内存称为直接内存)

虚拟机栈

栈的数据结构:FILO先进后出 虚拟机栈的作用:在JVM运行过程中存储当前线程运行方法所需的数据、指令、返回地址。 虚拟机栈是基于线程的:在线程的生命周期这,参与计算的数据会频繁的入栈和出栈,栈的生命周期和线程是一样的。 虚拟机栈的大小缺省为1M,可以参数 -Xss 调整大小,eg:-Xss256k

栈帧

在每个方法被调用的时候,都会创建一个栈帧,并入栈,一旦方法完成相应的调用,则出栈 栈帧大体包含四个区域(局部变量表、操作数栈、动态连接、返回地址) 1、局部变量表:主要存放我们Java的八大基础数据类型,对象的引用地址 2、操作数栈:存放java方法执行的操作数的,他就是一个栈,先进后出,操作的元素可以是任意的java数据类型。 3、动态连接:java语言特性多态 4、返回地址:正常返回(调用程序计数器这的地址作为返回),异常返回(通过异常处理表来确定) 同时,虚拟机栈这个内存也不是无限大他有大小限制,默认情况下是1M

程序计数器

较小的内存空间,当前线程执行的字节码的行号指示器:各线程之间独立存储,互不影响。 程序计数器是一块很小的内存空间,记录各个线程执行的字节码的地址,例如,分支、循环、跳转、线程恢复等都依赖于计数器。

栈帧的执行对内存区域的影响

在JVM中,基于解释执行的这种方式是基于栈的引擎吗,这个栈就是操作数栈。

运行时数据区及JVM的整体内存结构

本地方法栈

管理本地方法的调用,服务的对象是native方法

方法区

存放已被虚拟机加载的类的相关信息,包括类信息、静态变量、运行时常量池、字符串常量池。 方法区是JVM对内存的逻辑划分,在jdk1.8之后使用元空间来实现方法区。 常量池:存放编译期间生成的各种字面量和符号引用,字面量(字符串、基本类型常量(final修饰的变量)),符号引用则包括类和方法的权限的名(XX/XX/XX)

符号引用

编译时不知道引用类的实际内存地址,使用符号引用来代替。 而在类装载器装载该类时,可以通过虚拟机获取引用类的实际内存地址,也就是将符号引用替换为引用类的实际内存地址即直接引用地址。 即在编译时用符号引用来代替引用类,在加载时再通过虚拟机获取该引用类的实际地址。

常量池与运行时常量池

当类加载到内存之后,JVM就会将class文件常量池的内容存放到运行时常量池中;在解析阶段,JVM会把符号引用替换为直接引用(对象的索引值) 例如:类中的一个字符串常量在class文件中时,存放在class文件常量池中的;在JVM加载完类之后,JVM会将这个字符串常量放到运行时常量池中,并在解析阶段,指定该字符串对象的索引值,运行时常量池是全局共享的,多个类公用一个运行时常量池,class文件中的常量池多个相同的字符串在运行时常量池只会存在一份。 常量池有很多概念: 包括运行时常量池、class常量池、字符串常量池

元空间

java8为什么使用元空间替代永久代? 官方给出的解释是: 移除永久代是为了融合HotspotJVM 与JRockit VM 而做出的努力,因为JRockit没有永久代,所以不需要配置永久代。 永久代内存经常不够用或发生内存溢出,抛出异常OOM,这是因为jdk1.7版本中,指定PermGen区大小为8M,由于PermGen 中类的元数据信息在每次Full GC的时候都可能被搜集,回收率都偏低,还有为PermGen分配多大的空间很难确定。

常见的垃圾回收就是操作堆的 java对象可分为基本数据类型和普通对象 对于普通对象来说,JVM会首先在堆上创建对象,然后在其他地方使用的其实是他的引用。 对于基本数据类型,有两种情况,当你在方法体中声明了基本数据类型对象,他就会在栈上直接分配其他情况,都是在堆上分配。

堆大小参数

-Xms:堆的最小值 -Xmx:堆的最大值 -Xmn:新生代大小 -XX:NewSize:新生代最小值 -XX:MaxNewSize:新生代最大值

直接内存(堆外内存)

如果使用NIO,这块区域会被频繁使用,在java堆内可以用directByteBuffer对象直接引用并操作。 小结: 1、直接内存主要通过DirectByteBuffer申请内存。 2、其它堆外内存,主要使用了Unsafe或者其它JNI手段直接申请的内存 堆外内存泄漏是非常严重的,他的排除难度高,影响大,甚至造成主机死机

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JVM、JRE、JDK的关系
  • JVM的发展
  • JVM整体知识模块
  • JVM的内存区域
  • 虚拟机栈
  • 栈帧
  • 程序计数器
  • 栈帧的执行对内存区域的影响
  • 运行时数据区及JVM的整体内存结构
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档