弄懂JVM

1.class Loader(类加载器)

我们编写的java文件,编辑器会编译成*.class的字节码文件;在我们执行代码时,会由类加载器将文件加载到运行时数据区(内存)中去执行。
我们先来看一段简单的代码:

public class Test {
	public static void main(String[] args) {
		System.out.println(Test.class.getClassLoader());
	}
}

执行将打印如下内容:
打印
打印出了加载这个类所用到的类加载器为AppClassLoader,那么它具体是怎么加载的呢,加载过程是什么样的呢?
打开命令行工具,cd进入Test.class所在目录,执行java指令:java -verbose test.Test
打印
有没有一种很熟悉的感觉?对,首先打开了rt.jar,然后就去加载了Object类…
回到最开始执行代码打印的sun.misc.Launcher$AppClassLoader@73d16e93,在命令行中找到它:
打印
可以看出,加载了这么几个类 启动类加载器(bootstrapClassLoader)、扩展类加载器(ExtClassLoader)、系统类加载器(AppClassLoader)
在通过一段代码,探索一下他们的关系:
public class Test {
	public static void main(String[] args) {
		ClassLoader c = Test.class.getClassLoader();
		while(c != null) {
			System.out.println(c);
			c = c.getParent();
		}
	}
}

打印如下:
打印
很明显,AppClassLoader的上级为ExtClassLoader(注意:不是继承关系,只是一种组合关系)。那么ExtClassLoader的上级加载器是什么呢? 来看一下源码:
打印
打印
上面这段代码,synchronized保证了只有一个线程进行加载,然后loadclass方法是一个递归方法,一直找到最上层加载器才去进行加载(双亲委派机制),然后找不到上级的时候,最终去找到了一个native本地方法(根据操作系统不同,实现也不一样,一般为c++实现的,是java实现跨平台的原因),即我们的启动类加载器。
现在很清楚了,来总结一下,用下面的一张图进行说明:
打印
启动类加载器,负责将JAVA_HOME/lib下的类库(如rt.jar)加载到内存中,这是一个本地私有方法,不同通过程序引用去调用执行。
扩展类加载器,负责将JAVA_HOME/lib/ext或者由系统变量java.ext.dir指定位置的类库加载到内存。
应用程序类加载器(即系统类加载器,getSystemClassLoader()的返回值),负责将classpath类路径下的类加载到内存。

双亲委派机制: 加载时,自上而下;检查时,自下而上。 这也是java虚拟机为了保证程序执行安全的一种方式。下面我来简单解释一下:
来看一段代码,新建一个名称为List的类:
打印
这段代码虽然可以编译通过,但是却不能够正常执行。就是因为是自上而下加载的,List已经由上级加载器 加载过了(rt.jar中),就不能进行加载了。保证了在写出了不安全的程序时,JDK不让它执行。

2.Runtime Data Area(运行时数据区)

借助一张图来进行说明:
打印

  1. 堆。 对于大多数应用程序来说,堆是java虚拟机管理的内存中最大的一块。 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。 此区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。 如果堆中没有内存完成实例分配,并且堆也无法再扩展时,就会抛出OutOfMemoryError异常。
  2. 方法区。 此区域同样是线程共享的区域。 被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等都存储在这里。 当方法去无法满足内存分配需求时,会抛出OutOfMemoryError异常。
  3. 程序计数器。 是一块较小的内存空间,当前线程所执行的字节码行号指示器。
    进去cmd,执行指令: javap -c Test
    打印
    可以看到,编译后的每一条执行指令都有对应一个编号。 就是指向执行指令的地址,执行后做累加操作。使得程序按照一定的步骤去执行。
  4. 栈。 每当启动一个新线程的时候,java虚拟机都会为它分配一个栈。java以栈帧为单位来保存线程的运行状态。虚拟机只会为栈执行两种操作:以栈帧为单位的入栈和出栈。

最后,下面这张图对于大家进行jvm调优肯定会有帮助的:
打印
打印

打印


转载请注明: 不好听的博客 弄懂JVM

上一篇
Java内存模型(JMM) Java内存模型(JMM)
在面试中,面试官经常喜欢问:『说说什么是Java内存模型(JMM)?』面试者内心狂喜,这题刚背过:『Java内存主要分为五大块:堆、方法区、虚拟机栈、本地方法栈、PC寄存器,balabala……』面试官会心一笑,露出一道光芒:『好了,今天
2021-12-14
下一篇
初识python-爬取网页文字和图片 初识python-爬取网页文字和图片
学习了一下用python爬取网络上的文字和图片,在此记录一下。 1.下载“笔趣看”网页上的小说代码如下:# __*__ coding:UTF-8 __*__ import requests from bs4 import Beauti
2018-12-08
目录