【JVM虚拟机】(5)---深入理解JVM-Class中常量池
深入理解Class---常量池
一、概念
1、jvm生命周期
启动
:当启动一个java程序时,一个jvm实例就诞生了,任何一个拥有main
方法的class都可以作为jvm实例运行的起点。
运行
:main()函数作为程序初始线程起点,其它线程由该线程启动,包括守护线程(daemon)和non-daemon(普通线程)。守护线程是JVM自己使用的线程比如GC线程就是个守护线程,只要这个jvm实例还有普通线程执行,就不会停止,但是可以用exit()强制终止程序。
消亡
:所有非守护线程退出时,JVM实例结束生命,若安全管理器允许,程序也可以使用java.lang.Runtime类或者System.exit(0)来退出。实际上exit也是用到Runtime类来退出,Runtime是个神奇的类,它还可以用于启动和关闭非java进程。
2、JVM与Class文件
我们一直说java虚拟机实现的与语言是无关的
,java虚拟机不和包含java在内的任何语言绑定,它只和与class文件
这种特殊的二进制文件格式所关联,class文件中包含了java虚拟机指令集
和符号表
以及若干其他辅助信息。基于安全方面的考虑, Java 虑拟机规范要求在 Class 文件中使用许多强制性的语法和结构化约束
,但任一门功能性语言都可以表示为一个能被 Java 虚拟机所接受的有效的 Class 文件。作为一个通用的、机器无关的执行平台,任何其他语言的实现者都可以将 Java 虚拟机作为语言的产品交付媒介。例如,使用 Java 编译器可以把 Java 代码编译为存储字节码的 Class 文件,使用 JRuby 等其他语言的编译器同样可以把程序代码编译成 Class 文件,虚拟机并不关心Class 的来源是何种语言,如图。
3、什么是Class文件
Java字节码类文件(.class)是Java编译器编译Java源文件(.java)产生的“目标文件”。它是一种8位字节的二进制流文件, 各个数据项按顺序紧密的从前向后排列, 相邻的项之间没有间隙, 这样可以使得class文件非常紧凑, 体积轻巧, 可以被JVM快速的加载至内存, 并且占据较少的内存空间(方便于网络的传输)。
class文件是一组以8位字节为基础单位的二进制流。
class文件中的信息是一项一项排列的, 每项数据都有它的固定长度, 有的占一个字节, 有的占两个字节, 还有的占四个字节或8个字节, 数据项的不同长度分别用u1, u2, u4, u8表示, 分别表示一种数据项在class文件中占据一个字节, 两个字节, 4个字节和8个字节。
4、什么是魔数
当我们把class文件转成16进制,我们可以看到文件的头四个字节是cafe babe
,这个就称为魔数
。,它唯一作用就告诉虚拟机当前的文件就是class文件。
使用魔数而不是用扩展名来进行识别主要是基于安全考虑,因为扩展名我们可以随意通过重命名等方式改动。而通过魔数就算你把结尾改成.clss。但它同样还能在JVM运行,因为它的头部还是cafe babe
没变。
很多文件存储标准中都用魔数进行身份标识,如图片gif,jpeg都在文件头部中存储着魔数。
5、jvm常量池
我先讲下概念,接下来我会将class文件转为16进制流后,在举例说明。
常量池中每一项常量都是一个表,jdk1.8有14种结构不同的表结构,这14个表有个共同特点,就是表开始的第一位都是一个u1类型的标志位,JVM根据这个标志位[tag]来确定某个常量池项表示什么类型的字面量,比如tag为1就是指CONSTANT_utf8_info
再看常量池类型表:
这14种常量项结构还有一个特点是,其中13表占用得字节固定,只有CONSTANT_Utf8_info占用字节不固定
,其大小由length决定。为什么呢?因为从常量池存放的内容可知,其存放的是字面量和符号引用,最终这些内容都会是一个字符串,
这些字符串的大小是在编写程序时才确定,比如你定义一个类,类名可以取长取短,所以在没编译前,无法确定大小不固定,编译后,通过utf-8编码,就可以知道其长度。
在看每一项常量表对应的说明:
二、16进制class文件解析
先看java代码
package com.jincou.demo.domain;
public class XiaoXiao {
private String father;
public String fatherName() {
return "小小她爹";
}
}
通过命令自动生成class文件(会在同一目录生成)
javac XiaoXiao.java
在将class文件拖入文本编辑器里,显示自然就是16进制流了,如下:
上面的表其实可以划分为以下七个部分,.class 字节码文件包括:
- 魔数与class文件版本
- 常量池
- 访问标志
- 类索引、父类索引、接口索引
- 字段表集合
- 方法表集合
- 属性表集合
这篇博客只讲到常量池,其它的下篇讲,接下来我们一行一行解释,首先是:
cafe babe
:上面说过了这个是魔数,告诉JVM虚拟机我就是class文件。
0000 0034
:次版本号组成u2+主版本号u2。共占4个字节。0034转10进制为52,代表当前JDK版本为1.8。
0013
:说明有19-1即18个常量。
上面这些位置是固定的。接下来就是说明每一个常量:
0a
:这就是tag代表一个标志,0a代表10,去找常量池列表。
得知它是一个接口中方法的符号引用,然后去找CONSTANT_Methodref_info
对应常量列表描述:
从常量列表我们可以知道该类型一共占了5u,即0a00 0400 0f
,那么下一个tag就是08
代表字符串类型常量,以此类推就可以知道一共18个常量的信息。
三、class反编译
通过上面看16进制的却太麻烦了,现在我们可以通过JDK自带反编译工具查看会更加清晰。
javap -verbose 文件名
通过反编译看去就很直观,比如第一个字符常量很明显告诉你是CONSTANT_Methodref_info
,而且对于的就是4和15和上面完美对应。
最后思考,到底哪些会放到常量池?
1.常量池可以理解为class文件中的资源仓库,有很多种类型,主要存放两大常量
①.字面量
字面量就是通俗理解的java常量,如文本字符串,8大基本数据类型,final修饰的常量值等
②.符号引用
符号引用属于编译原理的概念,主要包含以下三种
1)类和接口的全限定名
2)字段的名称和描述符
3)方法的名称和描述符
参考
1、深入了解java虚拟机第2版第六章
只要自己变优秀了,其他的事情才会跟着好起来(少将3)
【JVM虚拟机】(5)---深入理解JVM-Class中常量池的更多相关文章
- JVM内部细节之三:字符串及字符串常量池
本人最近正在面试,然后注意到总是有公司喜欢考String的问题,如字符串连接有几种方式,它们之间有什么不同等问题:要不就是给一段代码问创建了几个对象.那么该不该问呢?我认为当面试有一定工作经验的求职者 ...
- java虚拟机学习-深入理解JVM(1)
1 Java技术与Java虚拟机 说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成: Java编程语言.Java类文件格式.Java虚拟机和Java应 ...
- 走进JVM【二】理解JVM内存区域
引言 对于C++程序员,内存分配与回收的处理一直是令人头疼的问题.Java由于自身的自动内存管理机制,使得管理内存变得非常轻松,不容易出现内存泄漏,溢出的问题. 不容易不代表不会出现问题,一旦内存泄漏 ...
- JVM笔记3-java内存区域之运行时常量池
1.运行时常量池属于线程共享区中的方法区. 2.运行时常量池用于编译期生成的各种自变量,符号引用,这部分内用将在类加载后接入方法区的运行时常量池中存放. 看如下代码所示,如图: public clas ...
- Java中常量池详解
在Java的内存分配中,总共3种常量池: 转发链接:https://blog.csdn.net/zm13007310400/article/details/77534349 1.字符串常量池(Stri ...
- 【JVM虚拟机】(8)--深入理解Class中--方法、属性表集合
#[JVM虚拟机](8)--深入理解Class中--方法.属性表集合 之前有关class文件已经写了两篇博客: 1.[JVM虚拟机](5)---深入理解JVM-Class中常量池 2.[JVM虚拟机] ...
- 【JVM虚拟机】(7)---深入理解Class中-属性集合
#[JVM虚拟机](7)---深入理解Class中-属性集合 之前有关class文件已经写了两篇博客: 1.[JVM虚拟机](5)---深入理解JVM-Class中常量池 2.[JVM虚拟机](6)- ...
- 【JVM虚拟机】(6)---深入理解Class中访问标志、类索引、父类索引、接口索引
JVM(6)访问标志,类索引 上一篇博客讲[JVM虚拟机](5)---深入理解JVM-Class中常量池 我们知道一个class文件正常可以分为7个部分: 魔数与class文件版本 常量池 访问标志 ...
- 深入理解JVM虚拟机-2自动内存管理机制
java虚拟机所管理的内存将会包括一下几个运行时数据区域. 程序计数器: 程序计数器是一块较小的内存空间.字节码解析式工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转 ...
随机推荐
- centos7虚拟机设置静态ip
cd /etc/sysconfig/network-scripts/ vi ifcfg-enp0s3 1.修改配置 BOOTPROTO=static2.新增配置(查询宿主机对应的信息) IPADDR= ...
- 拾人牙慧篇之——基于HTML5中websocket来实现消息推送功能
一.写在前面 要求做一个,后台发布信息,前台能即时得到通知的消息推送功能.网上搜了也有很多方式,ajax的定时询问,Comet方式,Server-Sent方式,以及websocket.表示除了定时询问 ...
- Excel常用的格式处理
你有没有碰到在Excel中设置了行高自适应后,部分行的行高太小,整体界面不美观的问题呢? 你有没有碰到Excel中的各个sheet页中的各列内容中都有不同个数的回车换行符,内容看起来参差不齐,不美观呢 ...
- nginx常用配置系列-反向代理
接上篇,反向代理的原理与用途很多地方有讲,用文字说再多可能也表达不清楚,下面贴一张拓扑图,介绍下什么叫反向代理 以上图有两种情景 1. 访问者的客户端是 local ,要访问baidu的服务器,bai ...
- SHELL脚本--expr命令全解
bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html expr命令可以实现数值运算.数值或字符串比较.字符串匹配.字 ...
- mysql读写分离总结
随着一个网站的业务不断扩展,数据不断增加,数据库的压力也会越来越大,对数据库或者SQL的基本优化可能达不到最终的效果,我们可以采用读写分离的策略来改变现状.读写分离现在被大量应用于很多大型网站,这个技 ...
- Java NIO核心组件简介
原文链接:http://tutorials.jenkov.com/java-nio/overview.html NIO包含下面几个核心的组件: Channels Buffer Selector 整个N ...
- Spring Security OAuth2 Demo -- good
1. 添加依赖授权服务是基于Spring Security的,因此需要在项目中引入两个依赖: <dependency> <groupId>org.springframework ...
- Javascript高级程序设计复习——第五章引用类型 【原创】
5.1 Object类型 1:创建Object实例的两种方式 ①new构造法 var obj1 = new Object(); 注意大写!不传递参数时可以省略圆括号 obj1.hehe = &quo ...
- 拿到6个重磅offer的大神,超详细面试经验总结
本人是国内某财经院校的小本,学校不算很有名,也没有很好的硬件条件,但是很幸运的在这样的就业大环境里拿了6个OFFER,其中包括一些股份制商业银行的总行,4大国有商业银行的省行,以及国内最一流国企的省公 ...