JVM基础知识(原创)

简介:

JVM简介

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。 JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。编译虚拟机的指令集与编译微处理器的指令集非常类似。

JDK内存

Java 的内存模型分为
Young(年轻代也叫new区)

Young分为 Eden 区和两个Survivor 区(from和to,这两个Survivor区大小严格一至),新的对象实例总是首先放在Eden 区,Survivor区作为Eden区和Tenure(终生代)的缓冲,可以向 Tenure(终生代)转移活动的对象实例。
Tenured(终身代,也叫old区)

Tenure中存放生命周期长久的实例对象,但并不是如它的名字那样是终生的,里面的对象照样会被回收掉。

Young和Tenure共同组成了堆内存,也就是heap内存或heap区。
Perm(永久代)
有些旧版本也叫作:New Old Perm 叫法不同,表达的意思却是基本相同。Perm则是非堆内存的组成部分。主要存放加载的Class类级对象如class本身,method,field等等。
Virtual区
在JVM启动时,就已经保留了固定的内存空间给Heap内存,这部分内存并不一定都会被JVM使用,但是可以确定的是这部分保留的内存不会被其他进程使用。这部分内存大小由 -Xmx 参数指定。
而另一部分内存在JVM启动时就分配给JVM,作为JVM的初始Heap内存使用。影响这个的参数是 -Xms ,如果 -Xms 指定的值比-Xmx 的小,那么两者的差值就是Virtual内存值。随着程序的运行,Eden区,Tenured区和Perm区会逐渐使用保留的Virtual空间。
如果没有具体指定,初始和最大堆内存将根据机器的内存计算得出。参数DefaultInitialRAMFraction 和 DefaultMaxRAMFraction 会影响最终的结果,如下表所示:
FormulaDefault
initial heap size memory / DefaultInitialRAMFraction memory / 64
maximum heap size MIN(memory / DefaultMaxRAMFraction, 1GB) MIN(memory / 4, 1GB)
可以看到堆内存默认值最大不会超过1G。
JVM会根据堆内存的使用情况自动决定何时扩张和缩减实际堆内存的大小,可以用VM参数 -XX:MinHeapFreeRatio= 和 -XX:MaxHeapFreeRatio= 使用堆内存空闲百分比来定义,一般在32位机器上的默认值如下:
ParameterDefault Value
MinHeapFreeRatio 40
MaxHeapFreeRatio 70
-Xms 3670k
-Xmx 64m
-Xms/-Xmx:
java heap并不是越大越好,对他的一般优化原则是够用的情况下,尽可能的小,因为太大的话会浪费内存,同时影响GC的效率。当空闲堆内存所占堆内存百分比低于40%,JVM就会试图扩张堆内存空间;当空闲堆内存所占堆内存百分比高于70%,JVM就会试图压缩堆内存空间。
ps:以上默认值在不同平台会有不同的值,如果是64位系统,这些值一般需要扩张30%,来容纳在64位系统下变大的对象。
GC

GC是Garbage Collection的缩写,即垃圾回收机制,在Java中开发人员无需使用指针来管理内存,GC是JVM对内存(实际上就是对象)进行管理的方式。
第一种为单线程GC,也是默认的GC。,该GC适用于单CPU机器。
第二种为Throughput GC,是多线程的GC,适用于多CPU,使用大量线程的程序。第二种GC与第一种GC相似,不同在于GC在收集Young区是多线程的,但在Old区和第一种一样,仍然采用单线程。-XX:+UseParallelGC参数启动该GC。
第三种为Concurrent Low Pause GC,类似于第一种,适用于多CPU,并要求缩短因GC造成程序停滞的时间。这种GC可以在Old区的回收同时,运行应用程序。-XX:+UseConcMarkSweepGC参数启动该GC。

第四种为Incremental Low Pause GC,适用于要求缩短因GC造成程序停滞的时间。这种GC可以在Young区回收的同时,回收一部分Old区对象。-Xincgc参数启动该GC。
不管采用什么算法,GC总是会导致应用暂停的,这个时间长短从毫秒到秒之间不等,因此会影响应用的相应时间,多长的停顿在接受范围内取决于应用的特征,可以通过设置GC停顿的时间来调整(注意只是期望的时间,而不是绝对)

相关调整的目标:
短生命周期的对象不要进入Old区
短生命周期的对象在minor GC的时候干掉
长生命周期的对象要放到Old区
长生命周期的对象可以被Full GC清理掉,但是Full GC要调整到尽量少发生

JVM中的ClassLoader

类加载器(class loader)用来加载java类到java虚拟机中。一般来说,java虚拟机使用java类的方式如下:Java源程序(.java文件)在经过java编译器编译之后就被转换成java字节代码(.class文件)。类加载器负责读取Java字节代码,并转换成java.lang.class类的一个实例。每个这样的实例用来表示一个java类。

Java程序是由许多独立的类文件组成的,每个文件对应于一个java类。此外,这些文件并非立即全部加载如内存,而是根据程序需要装入内存。ClassLoader便是JVM中将类装入内存的零件,用户可以定制自己的ClassLoader。JVM中缺省的ClassLoader可以完成将本地已文件系统装入类文件的任务。用户指定的ClassLoader可以拥有JVM缺省的ClassLoader所不具有的功能。例如:用户可以使用自己创建的ClassLoader从非本地硬盘或者从网络装入可执行内容。

java应用环境中不同的class分别由不同的ClassLoader负责加载。
一个jvm中默认的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分别各司其职:
Bootstrap ClassLoader:用来在JVM启动时加载核心类库,主要是 %JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等
Extension ClassLoader:负责加载java扩展类,主要是%JRE_HOME/lib/ext目录下的jar和class
App ClassLoader:负责加载当前java应用classpath变量中的所有类。
其中Bootstrap ClassLoader是JVM级别的,由C++编写;Extension ClassLoader、App ClassLoader都是java类,都继承自URLClassLoader超类。
Bootstrap ClassLoader由JVM启动,然后初始化sun.misc.Launcher ,sun.misc.Launcher初始化Extension ClassLoader、App ClassLoader。
下图是ClassLoader的加载类流程图,以加载一个类的过程类示例说明整个ClassLoader的过程。


Java 类加载器层次结构 
类加载器包含具有父类加载器和子类加载器的层次结构。父类加载器和子类加载器之间的关系类似于超类和子类之间的对象关系。引导类加载器是 Java 类加载器层次结构的根。Java 虚拟机 (JVM) 创建引导类加载器,它将加载 JVM 中包含的 Java Development Kit (JDK) 内部类和 java.* 包。(例如,引导类加载器加载 java.lang.String。)
扩展类加载器是引导类加载器的子类加载器。扩展类加载器加载 JDK 的扩展目录中包含的所有 JAR 文件。这是一种无需在类路径中添加条目即可扩展 JDK 的便捷方法。但扩展目录中的所有内容都必须是自包含的,且只能引用扩展目录中的类或 JDK 类。

系统类路径类加载器扩展 JDK扩展类加载器。系统类路径类加载器加载 JVM 类路径中的类。
加载类 
类加载器在加载类时使用委托模型。类加载器实现首先检查其缓存,查看是否已经加载所请求的类。由于不重复从磁盘中加载类,而是使用该类在缓存内存中的副本,所以,这种类验证可以提高性能。如果在类缓存中找不到该类,则当前类加载器会要求其父类加载器提供该类。仅当父类加载器也无法加载该类时,该类加载器才会尝试加载该类。如果某个类既存在于父类加载器中,又存在于子类加载器中,则将加载父类加载器中的类。遵循这种委托模型可以避免同时加载多份相同的类。加载多份相同的类会引发 ClassCastException。
类加载器会先要求其父加载器加载类,然后再尝试自己加载该类。

参考至:《叱咤风云:WebLogic企业级运维实战》戴冠平著

             http://longdick.iteye.com/blog/442213

             http://songyishan.iteye.com/blog/1135183

             http://hi.baidu.com/love200456/blog/item/9d4d70fbdc38c970024f564f.html

             http://blog.sina.com.cn/s/blog_677e5328010109a3.html
本文原创,转载请注明出处、作者
如有错误,欢迎指正
邮箱:czmcj@163.com

作者:czmmiao  文章出处:http://czmmiao.iteye.com/blog/1614446
相关文章
|
存储 缓存 Java
Java基础知识第二讲:Java开发手册/JVM/集合框架/异常体系/Java反射/语法知识/Java IO
Java基础知识第二讲:Java开发手册/JVM/集合框架/异常体系/Java反射/语法知识/Java IO
236 0
Java基础知识第二讲:Java开发手册/JVM/集合框架/异常体系/Java反射/语法知识/Java IO
|
存储 算法 前端开发
JVM - 基础知识
有两种方法,分别为:引用计数法和可达性分析法
138 0
|
存储 Java 编译器
JVM 基础知识
JVM 基础知识
136 0
JVM 基础知识
|
Java 关系型数据库 数据库连接
基于JVM的动态语言Groovy 基础知识汇总
在使用Java的过程中,和C#的语法相比有些还是比较麻烦,比如异常、get set等问题,毕竟Java的发展时间比C#长了很多,很多问题当初设计时没有考虑到,为了向前兼容,不得不保留一定的历史负担(如泛型的处理,java的擦除法实现就是后续的兼容考虑)。
1192 0
|
28天前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
232 1
|
2月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
43 4
|
18天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
27天前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80
|
28天前
|
Java
JVM运行时数据区(内存结构)
1)虚拟机栈:每次调用方法都会在虚拟机栈中产生一个栈帧,每个栈帧中都有方法的参数、局部变量、方法出口等信息,方法执行完毕后释放栈帧 (2)本地方法栈:为native修饰的本地方法提供的空间,在HotSpot中与虚拟机合二为一 (3)程序计数器:保存指令执行的地址,方便线程切回后能继续执行代码
21 3