谈谈java虚拟机
本文可作为北京圣思元深入java虚拟机的课堂笔记。
先看一个令人dan teng的面试题
public class Singleton
{
public static Singleton s=new Singleton();
public static int k1;
public static int k2=0;
private Singleton(){
k1++;
k2++;
}
public static void main(String[] args)
{
System.out.println(Singleton.k1);
System.out.println(Singleton.k2);
}
}
请问输出什么?
如果是下面这样呢?
public class Singleton
{
public static int k1;
public static int k2=0;
public static Singleton s=new Singleton();
private Singleton(){
k1++;
k2++;
}
public static void main(String[] args)
{
System.out.println(Singleton.k1);
System.out.println(Singleton.k2);
}
}
诸位看官莫急,咱们慢慢来从虚拟机的层次来看这个问题。
什么是虚拟机?虚拟机是干什么的?
这些资料大家百度,我就不赘述了。
虚拟机的生命周期
在以下几种情况下,java虚拟机将结束生命周期。
1 执行了System.exit()方法
通过查看api文档,我们exit的参数为int,当参数为0就是正常结束,否则就是非正常结束。
2 程序正常结束
3 程序执行过程中遇到异常或错误
4 操作系统出现错误
类的加载,连接与初始化
大体的图如下
加载: 查找并加载类的二进制数据
连接:
-验证 确保被加载的类的正确性
-准备 为类的静态变量分配内存,并将其初始化为默认值(int就是0 boolean就是 false 引用类型就是null)
-解析 把类中的符号引用变为直接引用
初始化: 为类的静态变量赋予正确的初始值
不知道诸位看官是否有什么疑问?
如果大家没有,我倒是有个问题,在我们最开始编写java的时候总是javac命令编译成class字节码,java命令运行。如果java代码有什么问题,在javac的时候就会抛出问题,换句话说等我们连接class文件的时候它肯定是没问题的,那还验证什么呀?
答案就是:
如果class的产生只能通过javac命令的话,那就没有任何问题了,可关键就是人们也可以手动产生class文件,所以验证这一步还是有用的。
第二个问题 在连接的准备阶段有把静态变量初始为默认值,但是在初始化的阶段也有为类的静态变量赋予正确的初始值。这两个步骤有什么关系?
看如下代码片
public class test{
public static int a=5;
public static int b;
public static int c;
static{
c=10;
}
public static Person p;
}
在准备阶段,a与b的值都是0(因为int型默认都是0) p为null(Person 就是简单的一个类)
到初始化阶段,a就是5了,b仍然是0,c是10,p还是null。
换句话说,只有在初始化阶段,赋值的=才发挥作用。(对a的赋值与下面的static代码块是一回事)
(准备阶段与初始化阶段对静态变量的赋值顺序,都是按照变量的书写顺序来的。上面的例子就是先给a再给b,然后c,最后p)
一步一步来
加载
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
如下图
类的加载的最终产品是位于堆区中的Class对象
这里就有另一个名词了Class对象。
就像每一本书有作者,价格等描述自身一些熟悉的信息,每个类也都有一个描述自己信息的东西,它就是class对象。
例如
public class Person{
public String name;
public String getName(){
return name;
}
}
这个类的Class对象里就包含了这个类里面有几个属性,每个属性是什么类型,有什么方法,每个方法的参数都是什么,返回值都是什么等等。
具体信息,参考api。
谈到类的加载,就得说说类的加载器了。
java中有两种类的加载器
– Java虚拟机自带的加载器
根类加载器(Bootstrap)
(用c++实现 大家都看不到)
扩展类加载器(Extension)
系统类加载器(System)
(扩展类加载器与系统类加载器是用java写的)
-用户自定义的类加载器
java.lang.ClassLoader的子类
用户可以定制类的加载方式
看如下代码片
Class c1=Class.forName("java.lang.String");
Class c2=Class.forName("Singleton"); //就是上面的那个Singleton
System.out.println(c1.getClassLoader());
System.out.println(c2.getClassLoader());
运行结果就是
null
sun.misc.Launcher$AppClassLoader@fb56b1
String是Bootstrap加载的,用c++写的我们看不到,所以是null
AppClassLoader就是系统加载器
连接之验证
类被加载后,就进入连接阶段。连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去。
如下图
连接之准备
上文已经解释。
连接之解析
如下图
至于什么是符号引用,大家在eclipse中,打开一个class文件
上面红框里面的就是符号引用
初始化
Java程序对类的使用方式可分为两种
主动使用
被动使用
所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用”时才初始化他们。
主动使用包含以下六种情况
创建类的实例 (如在代码中new Person())
访问某个类或接口的静态变量,或者对该静态变量赋值 (Singlean.a=8)
调用类的静态方法 (Singleton.getInstance();)
反射(如Class.forName(“com.shengsiyuan.Test”)
初始化一个类的子类 (有father类,有child类,且child继承或实现father类。 )
Java虚拟机启动时被标明为启动类的类(调用java启动命令 如Java Test)
除了以上六种,别的调用方法都是被动使用。
再说说最开始的那个题目
public static Singleton s=new Singleton();
public static int k1;
public static int k2=0;
private Singleton(){
k1++;
k2++;
}
在连接的准备阶段 k1,k2都是0,s是null
到了初始化阶段, s的初始化调用了构造函数
k1,k2都从0变成了1
继续往下阅读
public static int k1;
public static int k2=0;
k1没有被赋值还是1
但是k2却被赋值为0了
所以最后的结果就是
1
0
至于把
public static Singleton s=new Singleton();
放到后面,大家自己分析吧.
谈谈java虚拟机的更多相关文章
- 《深入理解Java虚拟机》读书笔记2--垃圾回收
回收哪些内存/对象 引用计数算法 可达性分析算法 finalize()方法 HotSpot实现分析 转载:http://blog.csdn.net/tjiyu/article/details/5398 ...
- java基础(一):谈谈java内存管理与垃圾回收机制
看了很多java内存管理的文章或者博客,写的要么笼统,要么划分的不正确,且很多文章都千篇一律.例如部分地方将jvm笼统的分为堆.栈.程序计数器,这么分太过于笼统,无法清晰的阐述java的内存管理模型: ...
- Java虚拟机垃圾回收:基础点(转载)
1.Java虚拟机垃圾回收 垃圾回收,或称垃圾收集(Garbage Collection,GC)是指自动管理回收不再被引用的内存数据. 在1960年诞生于MIT的Lisp语言首次使用了动态内存分配和垃 ...
- 《Java虚拟机原理图解》 1.2.3、Class文件里的常量池具体解释(下)
NO9.类中引用到的field字段在常量池中是如何描写叙述的?(CONSTANT_Fieldref_info, CONSTANT_Name_Type_info) 一般而言.我们在定义类的过程中会定义一 ...
- 每日一问:讲讲 Java 虚拟机的垃圾回收
昨天我们用比较精简的文字讲了 Java 虚拟机结构,没看过的可以直接从这里查看: 每日一问:你了解 Java 虚拟机结构么? 今天我们必须来看看 Java 虚拟机的垃圾回收算法是怎样的.不过在开始之前 ...
- 浅谈java虚拟机|系列1|架构简介
今天开了一个专题.谈谈我们java程序员每天面对的java虚拟机(jvm). 本质上来说,jvm分两部分:编译器(compiler)和运行时(runtime). 所谓的编译器,简单来说,他就是个翻译机 ...
- 《深入理解Java虚拟机》第2版挖的坑终于在第3版中被R大填平了
这是why技术的第34篇原创文章 本周还是在家办公的一周,上面的图就是我在家的工位,和上周<Dubbo Cluster集群那点你不知道的事>这篇文章里面的第一张图片比起来,升级了显示器支撑 ...
- 深入Java虚拟机--判断对象存活状态
程序计数器,虚拟机栈和本地方法栈 首先我们先来看下垃圾回收中不会管理到的内存区域,在Java虚拟机的运行时数据区我们可以看到,程序计数器,虚拟机栈,本地方法栈这三个地方是比较特别的.这个三个部分的特点 ...
- 【深入Java虚拟机】之四:类加载机制
类加载过程 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载.验证.准备.解析.初始化.使用和卸载七个阶段.它们开始的顺序如下图所示: 其中类加载的过程包括了加载.验 ...
随机推荐
- linux:CPU私有变量(per-CPU变量)
一.简介2.6内核上一个新的特性就是per-CPU变量.顾名思义,就是每个处理器上有此变量的一个副本.per-CPU的最大优点就是,对它的访问几乎不需要锁,因为每个CPU都在自己的副本上工作.task ...
- 使用kprobes查看内核内部信息
前言:使用printk打印变量等方法,是调试内核的有效方法之一,但是这种方法必须重新构建并用新内核启动,调试效率比较低.以内核模块的方式使用kprobes.jprobes,就可以在任意地址插入侦测器, ...
- RxJava(11-线程调度Scheduler)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51821940 本文出自:[openXu的博客] 目录: 使用示例 subscribeOn原理 ...
- 2016年年终CSDN博客总结
2015年12月1日,结束了4个月的尚观嵌入式培训生涯,经过了几轮重重面试,最终来到了伟易达集团.经过了长达3个月的试用期,正式成为了伟易达集团的助理工程师. 回顾一年来的学习,工作,生活.各种酸甜苦 ...
- 微信小程序基础之表单Form的使用
表单Form的应用很广泛,我们可以利用form设计登录注册,也可以设计一种答题问卷的形式,今天主要讲一下form的使用 form表单,将组件内输入的"switch","i ...
- React Native之ScrollView控件详解
概述 ScrollView在Android和ios原生开发中都比较常见,是一个 滚动视图控件.在RN开发中,系统也给我们提供了这么一个控件.不过在RN开发中 ,使用ScrollView必须有一个确定的 ...
- Android Stutio中使用java8的Lambda表达式
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51532028 本文出自:[openXu的博客] 目录: 为什么要使用Lambda表达式 让A ...
- J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP
J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言 搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理. ...
- hive分组排序 取top N
pig可以轻松获取TOP n.书上有例子 hive中比较麻烦,没有直接实现的函数,可以写udf实现.还有个比较简单的实现方法: 用row_number,生成排名序列号.然后外部分组后按这个序列号多虑, ...
- The type org.apache.http.HttpResponse cannot be resolved. It is indirectly referenced from required
在Android 6.0(API 23)中,Google已经移除了移除了Apache HttpClient相关的类.HttpResponse类.缺失jar包使用HttpResponse等会报错: Th ...