什么是JVM

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

JDK 、JER、JVM三者之间的关系

JDK(Java Development Kit)是针对Java开发员的产品,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。Java Runtime Environment(JRE)是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。JVM是Java Virtual Machine(Java虚拟机)的缩写,是整个java实现跨平台的最核心的部分,能够运行以Java语言写作的软件程序。

JVM 位置

jvm是运行在操作系统上的,而操作系统的下一层是硬件体系

Jvm的体系结构

  1. 方法区:是被所有线程共享的,属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、运行时的常量池存在方法区中
  2. 线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。
  3. 本地方法栈(native method stack)主要作用是登记native方法,然后在execution engine执行的时候加载本地方法库。
  4. 对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组。内部会划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)。可以位于物理上不连续的空间,但是逻辑上要连续。
  5. 每一个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区的方法字节码(用来存储指向一条指令的地址,即将要执行的指令代码)在执行引擎读取下一个指令,是一个非常小的内存空间。
  • 来一张图帮助大家理解每个区域存储的内容

类加载器

作用:加载class文件

这里我们首先要明白,类是一个模版,对象是具体的,写一段代码帮助大家理解

package jvm;public class Catr {//类是模版,,对象是具体的public static void main(String[] args) {Catr catr1 = new Catr();Catr catr2= new Catr();Catr catr3 = new Catr();System.out.println(catr1.hashCode());System.out.println(catr2.hashCode());System.out.println(catr3.hashCode());System.out.println(catr1.getClass().hashCode());System.out.println(catr2.getClass().hashCode());System.out.println(catr3.getClass().hashCode());}}


从hashcode的值我们可以清楚的知道,类的模版是同一个,而对象却不相同,这就是类是模版,对象是实列的解释。

  • 类加载器的分类
    1.Bootstrap classLoader:主要负责加载核心的类库(java.lang.*等),构造ExtClassLoader和APPClassLoader。
    2.ExtClassLoader:主要负责加载jre/lib/ext目录下的一些扩展的jar。
    3.AppClassLoader:主要负责加载应用程序的主函数类
package jvm;public class Catr {//类是模版,,对象是具体的public static void main(String[] args) {Catr catr1 = new Catr();Class<? extends Catr> aClass1 = catr1.getClass();ClassLoader classLoader = aClass1.getClassLoader();System.out.println(classLoader);//AppClassLoaderSystem.out.println(classLoader.getParent());//ExtClassLoaderSystem.out.println(classLoader.getParent().getParent());//null 的原因可能是 不存在 或者 java程序获取不到 rt.jar}}

双亲委派机制

在java包下新建一个lang包,创建一个String类

package java lang;
//双亲委派机制 保证安全
//1.先在AppClassLoader找->ExtClassLoader-.boot(最终执行)
public class String {public java.lang.String toString(){return "hello String";}public static void main(String[] args) {String string = new String();string.toString();}
}


这里是因为它根本就不是走的我们写的man方法,因为双亲委派机制会从AppClassLoader>ExtClassLoader->bootClassLoad一层一层的去找最终便会在bootClassLoad中找到所以便找到rt.jar包下的java.lang包下的Sring类。
如果我们定义一个没有被定义过得类呢?

public class Student {public String toString(){return "hello";}public static void main(String[] args) {Student student = new Student();System.out.println(student.toString());}
}

为了让大家更好的理解双亲委派机制,我们用一张图来解释

从上图中我们就更容易理解了,当一个Student.class这样的文件要被加载时。不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上。注意这个类似递归的过程,直到到达Bootstrap classLoader之前,都是在检查是否加载过,并不会选择自己去加载。直到BootstrapClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。

  • 双亲委派机制的作用
    1、防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
    2、保证核心.class不能被篡改。如果有人想替换系统级别的类:String.java,篡改它的实现,在这种机制下这些系统的类已经被Bootstrap classLoader加载过了(为什么?因为当一个类需要加载的时候,最先去尝试加载的就是BootstrapClassLoader),所以其他类加载器并没有机会再去加载,从一定程度上防止了危险代码的植入。

4、沙箱安全机制

Java安全模型的核心就是java沙箱,沙箱是一个限制程序运行的环境,沙箱机制就是将 java代码限定在java虚拟机(JVM)特定运行范围当中,并且严格限制代码对本地系统的访问,通过这样的措施来保证代码的有效隔离,防止对本地系统造成破坏,沙箱主要限制系统访问资源。
系统资源包括什么?
CPU、内存、文件系统、网络,不同级别的沙箱对这些资源的访问限制也可以不一样

native
public class Demo {public static void main(String[] args) {new Thread(()->{},"my thread name").start();}//凡是带了native关键词的,说明java的作用范围达不到了,回去调用底层C语言的库//                      会进入本地方法栈,调用本地方法接口JNI//JNI 扩展java的使用,融合不同的编程语言,为java所用,最初是为了调用C和C++的程序//java在内存区域专门开辟了一块标记区域,native method stack,登记native方法//在最终执行的时候加载本地方法库中的方法通过JNI//java程序驱动打印机会用到nativeprivate native void start0();
}

  • 栈是一种数据结构
  • 栈:先进后出
  • 栈内存主管程序的运行,生命周期和线程同步(通俗的将 程序执行栈里面的东西,栈里面是空的程序就结束了)
  • 线程结束栈内存也就释放了,对于栈来说不存垃回收的问题(线程结束 栈就空了)

为什么main方法先执行最后结束
因为程序一开始首先加载main方法,再由main方法调用其他的方法
eg:我们写段代+图来分析一下

public class Test{public static void main(String args[]){Test t = new Test();
t.test
}
public void test(){System.out.println("test")
}
}

栈会先加载main方法

然后加载test方法

执行完后先把test拿出去最后才能把main拿出去
再来深入理解一下栈的运行原理,这便要涉及到栈帧

下面再来看看 栈+堆 + 方法区:交互关系

三种JVM

  • sun公司的HotSpot Java HotSpot™ 64-Bit Server VM (build 25.131-b11, mixed mode)
  • BEA JRockit
  • IBM J9Vm
    我们一般用的都是HotSpot

  • 一个JVM只有一个堆内存,堆内存的大小是可以调节的

  • 类加载器读取到类文件后,一般会把什么东西放到堆中呢?(类、方法、常量、变量、保存我们所有引用类型的真实对象)

  • 堆内存还要细分为三个区

  • gc垃圾回收主要是在伊甸园区 和养老区

堆内存调优

经过研究,有99%的对象都是临时对象
永久区:
这个区域这区域常驻内存的,用来存放JDK自身携带的Class对象,interface元数据
,存储的是java运行时的一些环境或类信息,这个区域不存在垃圾回收,关闭vm虚拟机就会释放这个区域的内存
一个启动类加载了大量的三方jar包。Tomcat部署了太多的应用,大量动态生成的反射类不断地被加载,就会出现OOM

Jdk1.6之前:永久代 常量池是在方法区
Jdk1.7: 永久代 ,但是慢慢的淡化了,去永久代 常量池是在堆中
Jdk1.8:无永久代,常量池在元空间

  • 元空间:逻辑上存在,物理上不存在
  • 扩大堆内存

发生OOM的原因:我们来写一个程序并将内存改小得到以下错误

package jvm;import java.util.Random;public class Demo01 {public static void main(String[] args) {String str = "xiaotianw";while(true){str += str + new Random().nextInt(888888888) + new Random().nextInt(888888888);}}
}



这个错误就是OOM堆内存不足的错误

在一个项目中,突然出现OOM,那么改如何排除 研究为什么出错

我们一般会采用两种方式

  • 1 能够看到代码第几行出错:内存快照分析工具,AMT、Jprofiler
  • 2 Dubug 一行行分析代码
    AMT、Jprofiler作用
    1分析Domp内存文件。快速定位内存泄漏
    2获得堆中的数据
    3获得大的对象
  • 用JProfiler分析内存问题
    1.在IDEA 下载内置jprofiler 插件
    2.下载jprofiler 在IDEA的jprofiler插件配置下载的jprofiler路径

    我们来写一个程序利用JProfiler来分析到底是那一行出问题了
package jvm;import java.util.ArrayList;
//-Xms1m  -Xmx8m  -XX:+HeapDumpOnOutOfMemoryError
//-Xms设置初始化内存分配大小 默认1/64
// -XX:+PrintGCDetails 打印GC垃圾回收
//  -Xmx 设置最大分配内存 默认1/4
//-XX:+HeapDumpOnOutOfMemoryError oom dump
public class Demo03 {byte[] arry = new byte[1*1024*1024];//1mpublic static void main(String[] args) {ArrayList<Object> list = new ArrayList<>();int count =0 ;try{while(true){list.add(new Demo03());count ++;}}catch (Exception e){System.out.println("count:"+count);e.printStackTrace();}}
}

修改堆内存,造成OOM,参数-XX:+HeapDumpOnOutOfMemoryError是导出OOM错误

运行程序,在程序路径找到dump出的文件

点击在文件夹打开

按打开文件路径一层一层向上找,找到java_pid15828.hprof,双击打开

GC常用算法

JVM在进行GC时,并不是对这三个区域统一回收,大部分回收都是新生代
新生代
幸存区(from to)
老年代
GC两种:轻GC(普通GC) 重GC(全局GC)
GC的算法
标记清除法
标记压缩法
复制算法
引用计数器

  • 引用计数法:
  • 复制算法
    这里要明白幸存to(幸存1区) 和(幸存from幸存0区),总有一个要保持为空,比如第一次幸存下来的对象存入了幸存from区,第二次会将第二次幸存下来的对象连同一次幸存的对象一起存入幸存to区,这时候幸存from区便成为幸存to区,幸存to区变成了from区这是因为幸存to区和幸存from区会来回交换,且谁空谁是to

    好处:没有内存的碎片
    坏处: 浪费空间(浪费了一个幸存区的空间 因为幸存区总有一个是空的)
    复制算法最佳使用时间:对象存活度较低的时候
  • 标记清除算法:

  • 缺点:两次扫描严重浪费时间,会产生内存碎片
    优点:不需要额外空间
  • 标记清除压缩:

    先标记清除几次然后在进行压缩
    总结
    内存效率 复制算法> 标记清除算法> 标记压缩算法 (时间复杂度)
    内存整齐度 复制算法 =标记压缩法 >标记清除法
    内存利用率:标记压缩=标记清除>复制算法

年轻代:存活率低 复制算法
老年代: 存活率高 区域大 (标记清除(前提内存碎片不是太多)+标记压缩混合实现)

JVM入门就看这一篇相关推荐

  1. 关于做Kaggle比赛入门,看完这篇就够了

    PART 0 : Kaggle 介绍 Kaggle的数据挖掘比赛近年来很火,以至于中国兴起了很多很多类似的比赛 Kaggle 是一个数据科学竞赛的平台,很多公司会发布一些接近真实业务的问题,吸引爱好数 ...

  2. 别再说自己不会JVM了,看完这篇能和面试官扯上半小时

    作者:JonesYang 链接:出自 来源:掘金 前言 如果本篇文章有错,欢迎各路大神疯狂diss--当然喽,如果你看了这篇文章有所收获,那就疯狂点赞吧,你的点赞就是对我的最大鼓励.可以顺便加个关注哦 ...

  3. Kaggle入门,看这一篇就够了

    转载地址:https://zhuanlan.zhihu.com/p/25686876 之前发表了这篇关于 Kaggle 的专栏,旨在帮助对数据科学( Data Science )有兴趣的同学们更好的了 ...

  4. 关于Kaggle入门,看这一篇就够了

    这次酝酿了很久想给大家讲一些关于Kaggle那点儿事,帮助对数据科学(Data Science)有兴趣的同学们更好的了解这个项目,最好能亲身参与进来,体会一下学校所学的东西和想要解决一个实际的问题所需 ...

  5. Apache Spark处理大数据入门,看这一篇就够了

    作者 Srini Penchikala ,译者 丛一 什么是Spark Apache Spark是一个围绕速度.易用性和复杂分析构建的大数据处理框架.最初在2009年由加州大学伯克利分校的AMPLab ...

  6. 总结篇」别再说自己不会JVM了,看完这篇能和面试官扯上半小时(上)

    前言 周志明那本<深入理解 JAVA 虚拟机>翻了一遍又一遍,终于鼓起勇气在这里写下关于 JVM 的博客!!!现在,我要开始把我所理解到的记录在这里,和各位朋友一起分享!!! 我相信点开这 ...

  7. python自动化测试看什么书-Python自动化测试入门,看这一篇就足以

    第一时间关注 Python 技术干货! 阅读文本大概需要 5 分钟. 上篇文章讲了自动化测试的重要性,今天就给大家讲讲自动化框架 Robot Framework 的安装和 demo 演示. 为什么选择 ...

  8. 关于数据可视化入门,看这一篇够了

    本篇要点: 01.数据可视化是什么 02.数据可视化的一般流程 03.常见的数据种类 04.通过可视化你想表达什么信息 05.选择具体的可视化形式 06.图表设计原则 07.常用的可视化工具 01|数 ...

  9. python自动化测试-Python自动化测试入门,看这一篇就足以

    第一时间关注 Python 技术干货! 阅读文本大概需要 5 分钟. 上篇文章讲了自动化测试的重要性,今天就给大家讲讲自动化框架 Robot Framework 的安装和 demo 演示. 为什么选择 ...

最新文章

  1. 苹果M1芯片升级果然很炸场:性能暴涨功耗速降!但最香新品竟是无降噪AirPods 3...
  2. Python编程基础:第三十五节 文件删除Delete a File
  3. mysql-二进制日志
  4. 数字语音信号处理学习笔记——绪论(2)
  5. 后台开发人员面试内容——数据库(二)
  6. shell编程之条件语句(文件测试,test命令,字符串和逻辑测试,if单支语句,if双支语句,if多支语句,case命令,用if写跑步小实验)
  7. AcWing 523. 组合数问题
  8. python二分法查找程序_Python程序查找地板划分
  9. Spring中的@ImportResource
  10. 用dockers实现mysql主从同步
  11. 计算机 怎么挂 两块 硬盘,双硬盘怎么安装?电脑双硬盘安装教程
  12. windows10pygame下载安装问题描述
  13. 为什么安装了python桌面没有图标怎嘛办_安装了软件找不到图标怎么办_电脑软件安装了为什么不见图标...
  14. a与a的共轭转置相乘_线性代数A矩阵乘以A的转置的含义或者几何意义
  15. 音视频开发系列(2)PCM音量控制(高级篇)
  16. 2012年8月22日
  17. 中国商用机身组件市场趋势报告、技术动态创新及市场预测
  18. STM32+DAC8830驱动程序
  19. for in 用法
  20. 黑马VUE快速入门笔记

热门文章

  1. 大学课程设计:邮件系统
  2. 怎样成为一名销售高手?
  3. 视频语音转文字神器,使用体验感受评测
  4. GVoice AI Codec落地《和平精英》,腾讯AI Lab、腾讯游戏CROS联合打造移动端「超音速」语音体验...
  5. Effective Modern C++ 纯人工翻译,持续更新,不为博你眼球,旨在自我提升
  6. 字符(字符串、相关概念)
  7. office 论文 页码_八个步骤教你用Word写论文从任意页添加页码
  8. 麦肯锡思维的一点感触
  9. Zend Framework 2核心概念-DI(Dependency Injection)讲解
  10. 重温JavaSE(为JavaEE项目开发做准备)