大家好,欢迎来到IT知识分享网。
JVM
一.JVM初识
jvm简介
Java类加载器(ClassLoader)及双亲委派
类加载器
classloader顾名思义,即是类加载。虚拟机把描述类的数据从class字节码文件加载到内存,并对数据进行检验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型
执行流程
public class Test {
public static void main(String[] args) {
Test test = new Test(); System.out.println(test.getClass()); Class<? extends Test> testClass = test.getClass(); System.out.println(testClass.getClassLoader()+" 系统类加载器 (AppClassLoader)"); System.out.println(testClass.getClassLoader().getParent()+" 扩展类加载器 (Extension ClassLoader)"); System.out.println(testClass.getClassLoader().getParent().getParent()+" 启动类加载器 (Bootstrap Classloader)"); } }
执行结果
classloader双亲委托机制
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false); } // -----??----- protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// 首先,检查是否已经被类加载器加载过 Class<?> c = findLoadedClass(name); if (c == null) {
try {
// 存在父加载器,递归的交由父加载器 if (parent != null) {
c = parent.loadClass(name, false); } else {
// 直到最上面的Bootstrap类加载器 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) {
// If still not found, then invoke findClass in order // to find the class. c = findClass(name); } } return c; }
执行流程
当一个Hello.class这样的文件要被加载时。不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上。注意这个类似递归的过程,直到到达Bootstrap classLoader之前,都是在检查是否加载过,并不会选择自己去加载。直到BootstrapClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。
双亲委派的好处
堆
堆栈的区别
- 物理地址: 堆的物理地址分配对对象是不连续的。因此性能慢些。 栈使用的是数据结构中的栈,先进后出的原则,物理地址分配是连续的。所以性能快。
- 内存分别: 堆因为是不连续的,所以分配的内存是在 运行期 确认的,因此大小不固定。一般堆大小远远大于栈。栈是连续的,所以分配的内存大小要在 编译期 就确认,大小是固定的。
- 存放的内容: 堆存放的是对象的实例和数组。因此该区更关注的是数据的存储
栈存放:局部变量,操作数栈,返回结果。该区更关注的是程序方法的执行。 - 程序的可见度 堆对于整个应用程序都是共享、可见的。
栈只对于线程是可见的。所以也是线程私有。他的生命周期和线程相同。 - GC机制:针对的是堆
栈内存,主管程序的运行,生命周期和线程同步,线程结束,栈内存也就释放,对于栈来说,不存在垃圾回收问题,一旦线程结束,栈就over
堆的分区
- Eden区:新对象都是在此new出来的
- 老年代区:经过GC机制未清理的对象(长期存活的对象或者新生代无法容纳的大对象)进入老年代
- 元空间:逻辑上存在,物理上不存在这个区域常驻内存,用来存放JDK自身携带的Class对象,Interface元数据,java运行时的一些环境或类信息,不存在垃圾回收,关闭JVM就会释放这个区域的内存
元空间的发展历程: 1.6之前 永久代 常量池是在方法区中 1.7永久代 但慢慢退化了-有了去永久代的想法 常量池在堆中 1.8后 无永久代 常量池在元空间中 老年代中的对象: 年龄达到一定的程度(默认是15)的对象 在 survivor 空间中相同年龄所有对象大小的总和>survivor空间的一半
二.JVM调优
gc垃圾回收机制
调优目的
使用较小的内存占用来获得较高的吞吐量或者较低的延迟。
重要指标
- 内存占用:程序正常运行需要的内存大小。
- 延迟:由于垃圾收集而引起的程序停顿时间。
- 吞吐量:用户程序运行时间占用户程序和垃圾收集占用总时间的比值。
调优
根据内存调优
错误用例
public class Demo {
public static void main(String[] args) {
String str=""; while (true){
str+=str+new Random().nextInt()+new Random().nextInt(); } } }
先设置jvm的属性
-Xmx1024m:设置JVM最大可用内存为1024M。
-Xms1024m:设置JVM促使内存为1024m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-XX:+PrintGCDetails 用于打印输出详细的GC收集日志的信息.
报错信息
解决方案
- 先尝试扩大堆内存看结果
- 分析内存,看一下那个地方出现了问题(专业工具)
常用JVM参数参考
-Xms2g:初始化推大小为 2g; -Xmx2g:堆最大内存为 2g; Xms 是设置初始化内存分配大小 默认是1/64 Xmx 是设置最大分配内存 默认是1/4 -XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4; -XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2; –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合; -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合; -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合; -XX:+PrintGC:开启打印 gc 信息; -XX:+PrintGCDetails:打印 gc 详细信息。
gc垃圾回收设置优化
G1的适用场景
- 面向服务端应用,针对具有大内存、多处理器的机器。(在普通大小的堆里表现并不惊喜)
- 最主要的应用是需要低GC延迟并具有大堆的应用程序提供解决方案(G1通过每次只清理一部分而不是全部Region的增量式清理来保证每次GC停顿时间不会过长)
- 在堆大小约6GB或更大时,可预测的暂停时间可以低于0.5秒
用来替换掉JDK1.5中的CMS收集器,以下情况,使用G1可能比CMS好
– 超过50% 的java堆被活动数据占用
– 对象分配频率或年代提升频率变化很大
– GC停顿时间过长(大于0.5至1秒) - 从经验上来说,整体而言:
– 小内存应用上,CMS大概率会优于 G1;
– 大内存应用上,G1则很可能更胜一筹。
– 这个临界点大概是在 6~8G 之间(经验值)
其他收集器适用场景
- 如果你想要最小化地使用内存和并行开销,请选择Serial Old(老年代) + Serial(年轻代)
- 如果你想要最大化应用程序的吞吐量,请选择Parallel Old(老年代) + Parallel(年轻代)
- 如果你想要最小化GC的中断或停顿时间,请选择CMS(老年代) + ParNew(年轻代)
jvm调优步骤
监控分析
分析GC日志及dump文件,判断是否需要优化,确定瓶颈问题点。
如何生成GC日志
生成GC日志 -XX:+UseG1GC 代表使用G1垃圾收集器 -XX:MaxGCPauseMillis=100 垃圾收集最大停顿时间 -Xmx256m 代表堆内存最大大小 -XX:+PrintGCDetails 输出GC详细信息 -XX:+PrintGCTimeStamps 打印GC时间戳 -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC 代表执行GC前和之后堆内存状态 -Xloggc:G:\y2\JVM专题\gc.log 代表日志输出目录
产生dump文件
生成dump配置
准备工作
- idea先下载JProfiler工具
- JProfiler官网下载软件
- idea中设置JProfiler
java OOM错误示例
public class Demo {
public static void main(String[] args) {
String str=""; try {
while (true){
str+=str+new Random().nextInt()+new Random().nextInt(); } }catch (Error e){
e.printStackTrace(); } } }
java 运行jvm配置
-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
java 运行结果
java 生成dump文件
查看dump文件
双击打开*.hprof文件
后续待更
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/142470.html