深度理解JVM

 

1. 环境搭建

   安装jdk

 

 

2. 内存溢出场景模拟

public class Test01 {

public static void main(String[] args) {

//测试内存溢出

List<Demo> list = new ArrayList<Demo>();

while(true) {

list.add(new Demo());

}

//不停的创建对象会一直消耗堆内存知道内存消耗完(其实不会真的将8G的内存都消耗完)

//当达到一个上线时就会报出这个错误了,这时就会报出一个内存溢出

//OutOfMemoryError

}

}
class Demo{
}

 

可以在你的项目下找到这个快照的错误文件

 

但是我们是看不懂的所以需要到http://www.eclipse.org/mat/downloads.php去下载一个eclipseMemoryAnalyzer分析工具

如果你直接下载会非常慢所以选择一个其他的镜像这样下载就会快点

 

下载解压后打开

 

点击file->Open Heap Dump 选中产生的那个文件

 

然后生成一个

 

 

选中这个图标可以查看我们的堆内存运行情况 加载堆内存的信息

 

 

这个就代表很可能在main里面出现问题了 占得百分比高达95.6%

 

Shallow Heap 对象本分所占用的内存大小不包含它的引用对象

Retained Heap 代表当前对象的大小包括当前可直接或者间接引用对象的大小的总和。

点开那个占用堆内存最多线程

 

继续点开会发现 他创建了很多个这样的对象造成的堆内存溢出

Jvm 的可视化监控工具 这个工具在哪呢在我们安装的jdk中

因为我们的jdk已经配置在我们的path路径下因此在任何路径下都可以访问的到所以在

命令行中可以输入这个值 会将这个可视化界面弹出来

我们可以看到这个图像化界面只有18k那么真正的代码放在了lib目录下的一个jar包里面

 

这个jps这个命令会列出来所有的java进程,我们看到有JConsole 这个进程 但是为什么没有jps这个进程呢是因为

这个命令执行完之后就结束了。

当我们点进去就能对这个进程进行监控

我们大概就能看到这样的窗口了

 

 

 java 发展史

  1. 1996 . 1 jdk1.0 包含了jvm

  2. 1996.9 首届 java one 大会
  3. 1997.2  jdk 1.1 此时提出了内部类,反射,jar的文件格式 jdbc  JavaBeans,等也都得到了相应的发展。
  4. 1998 Jdk1.2 有了3个方向 J2EE(企业级)   J2ME(移动开发)   J2SE(桌面)
  5. 2000 .5  jdk 1.3

  6. 2002 .2 jdk 1.4 struts,lHibernate spring1.x  

正则表达式

NIO

日志

Xml 解析器

7.2004 . 9 jdk 1.5 自动装箱 泛型 注解  枚举 变长参数  增强for循环 

8.2006  jdk 1.6    JavaEE  JavaSE JavaME  jdk6 

提供脚本语言支持

提供了编译api 以及http 服务器api

9. 2009 jdk1.7  Lambda   Sun公司 以74亿被收购

Java 之父

詹姆斯  高林斯

 

Java技术体系

  Java程序设计语言

  各硬件平台上的java虚拟机

Class文件格式

Java API

第三方的java 类库

 

Jvm 虚拟机的发展  VMMemeory Management

 

Sun Classic VM

    世界上第一款商用的JVM 已经被淘汰了(只能使用纯解释器方式来执行java 代码如果要使用编译器就需要进行外挂,如果外挂了编译器那么这个编译器就会完全接管虚拟机    的执行系统,解释器便不再工作了。)

Exact VM(准确式 内存管理)

   解释器和编译器混合工作以及两级即时编译器 只在Solaris平台发布  英雄气短

   性能比Sun Classic VM 高。

 

Hotspot VM

(内置了编译器)

    以方法为单位进行编译。。。。

 

KVM (kilobyte)

   简单,轻量,高度可移植

在手机平台运行

JRockit

BEA 公司被Oracle 收购了(JRockit Mission Controller):用来诊断泄露并指出根本原因,该工作的开销非常小,因此可以使用他来寻找生产环境中的系统的内存泄漏。它包括三个独立的应用程序,内存泄漏检测器,JVM运行时分析器 和管理控制台。

世界上做快的java 虚拟机 专注服务器端应用

 优势:

垃圾收集器MissionControl服务套件

J9

    IBM  

IBM Technology for java virtual Machine IT4j

 

Azul VM

   高性能的java虚拟机

 

Liquid VM

 

Dalvik VM

    安卓系统所使用的 没有遵循JVM的规范使用的寄存器架构 不是使用JVM的栈架构

使用java 语言进行的开发。谷歌的,效率也比较高。

 

Microsoft JVM

    

 

    1. Class Loader 类加载器
    2. Execution Engine 执行引擎 负责解析命令,提交操作系统执行
    3. Native Interface 本地接口
    4. Runtime data area 运行数据区

本地方法接口中存放的是 java native interface (JNI)  native方法是一种使用java声明c实现的代码

java 代码执行到含有native的方法时就不在执行而是 调用操作系统的本地方法库交给操作系统和CPU

本地库接口java可以直接调c 我们可以使用double zookle 这些服务型框架避免了底层语言的沟通,

     

JVM是运行在操作系统之上的,它与硬件没有直接的交互

所谓的JVM调优就是调的是运行时数据区

 

    1. Class Loader 类加载器

负责加载class文件,class文件在文件开头有特定的文件标示,并且ClassLoader只负责class文件的加载,

至于它是否可以运行,则由Execution Engine决定 

    

 

 2. Execution Engine 执行引擎负责解释命令,提交操作系统执行。

3. Native Interface 本地接口

 

Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。
本地接口的作用是融合不同的编程语言为Java所用,它的初衷是融合 C/C++程序,Java诞生的时候是C/C++横行的时候,要想立足,必须有调用C/C++程序,于是就在内存中专门开辟了一块区域处理标记为Native的代码,它的具体做法是Native Method Stack中登记Native方法,在Execution Engine 执行时加载Native libraries。(例如:必须在迅雷下载视屏一样需要先装了迅雷才能让你下视屏

 

目前该方法使用的越来越少了,除非是与硬件有关的应用,比如通过Java程序驱动打印机或者Java系统管理生产设备,在企业级应用中已经比较少见。因为现在的异构领域间的通信很发达,比如可以使用Socket通信,也可以使用WebService等等,不多做介绍。

4. Runtime data area 运行数据区

1)方法区(Method Area

      1: 方法区是线程共享的,通常用来保存装载的类的元结构信息。

比如:运行时常量池+静态变量+常量+字段+方法字节码+在类/实例/接口初始化用到的特殊方法等。

       或者:静态变量+常量+类信息+运行时常量池存在于方法区中+实例变量存在堆内存中

          简单说,所有定义的方法的信息都保存在该区域。

JVM的优化99%就是优化堆,1%是优化方法区。整个JVM只有这个区域可以优化。

2:通常和永久区关联在一起(Java7之前),但具体的跟JVM的实现和版本有关。

(2)PC Register 程序计数器

每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下 

一条指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,

几乎可以忽略不记。

 

5.Native Method Stack

      它的具体做法是Native Method Stack中登记native方法,在Execution Engine执行时加载本地方法库。

 6. 栈

栈也叫栈内存,主管Java程序的运行,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束该栈就Over,生命周期和线程一致,是线程私有的。基本类型的变量、实例方法、引用类型变量都是在函数的栈内存中分配。

栈管运行 堆管存储

Exception in thread "main" java.lang.StackOverflowError

 

1.1 栈存储什么?

栈帧中主要保存3类数据:

本地变量 (Local Variable) :输入参数和输出参数以及方法内的变量;(输入参数就是形参,输出参数就是返回值)

栈操作 (Operand Stack): 记录出栈入栈的操作;

栈帧数据 (Frame Data):包括类文件,方法等等。

1.2 栈运行原理

栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法

Method)和运行期数据的数据集,当一个方法A被调用时就产生了一个栈帧F1,并被压入栈中,A方法有调用B方法,于是产生栈帧F2也被压入栈中.......。执行完毕后遵循先进后出的方式弹出栈帧。线程结束,栈释放

1.3 栈空间的基本组成单元

 

栈空间的基本组成单元是栈帧每调用一个方法在栈空间中就会有一个新的栈帧入栈,当方法结束时对应的栈帧就会出栈

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-08-21 11:48  纳兰容若♫  阅读(151)  评论(0编辑  收藏  举报