JVM

1.1JVM概念
1).虚拟机简介:
JVM( Java Virtual Machine的简称。意为Java虚拟机。): 虚拟机:
指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。 常见的虚拟机:
JVM、VMwave、Virtual Box
2).JVM和其他两个虚拟机的区别: a.VMwave与VirtualBox是通过软件模拟物理CPU的指令集,物理系统中会有很多的寄存器
b.JVM则是通过软件模拟Java字节码的指令集,JVM中只是主要保留了PC寄存器,其他的寄存器都进行了裁剪JVM是一台被定制过的现实当中不存在的计算机。
1.2Java和JVM发展简史
1).20世纪Java发展:
1996年SUN JDK 1.0时发布:Classic VM 纯解释运行,使用外挂进行JIT(编译器)
1997年JDK 1.1发布:
AWT、内部类、JDBC、RMI、反射( Java的核心)
RMI:远程方法调用(Remote Method Invocation)。能够让在某个java虚拟机上的对象像调用本地对象一样调用另一个java 虚拟机中的对象上的方法。
1998年JDK 1.2发布:Solary Exact VM(仅存在了很短的时间)
JIT和解释器混合执行 Accurate Memory Management 精确内存管理,数据类型敏感 提升GC性能
JDK1.2开始成为Java2( J2SE,J2EE,J2ME出现),并且加入了Swing Collection。2).二零零几年:
2000年JDK1.3:HotSpot作为默认虚拟机发布

2002年JDK1.4:Classic VM退出历史舞台
1.4更新内容:Assert,正则表达式,NIO,IPV6,日志API,加密类库,异常链,XML解析器等。
2004年JDK1.5即JDK5,Java5(很重要的一个版本)
Java5更新内容:泛型,注解,装箱,枚举,可变长参数,Foreach循环。 虚拟机层面:改进了Java内存模型( JMM),提供了JUC并发包。
JDK1.6 java6:
更新内容:脚本编程的支持(动态语言支持),JDBC4.0,Java编译器API,微型Http服务器API等。虚拟机层面:锁与同步,垃圾收集,类加载等算法的改动
3).二零一几年:
2011年JDK1.7/Java7发布: G1收集器(Update4才正式发布) 加强对非Java语言的调用支持 升级类加载器架构 64位系统压缩指针 NIO2.0
2014年Java8发布: Lamda表达式 语法增强 Java类型注释等
4).Java与JVM发展历史中的大事件:
使用最广泛的JVM为HotSpot HotSpot最早为Longview Technologies开发,被SUN收购2006年,Java开源,并建立OpenJDK HotSpot成为SUN JDK和OpenJDK中所带的虚拟机2008年,Oracle收购BEA 得到JRockit VM
2010年Oracle收购SUN 得到HotSpot
Orcale宣布在JDK8时整合HotSpot和JRockit VM,优势互补 在HotSpot的基础上移植JRockit的优秀特性
2.Java内存区域与内存溢出异常

2.1运行时数据区域
JVM会在执行Java程序的过程中把它管理的内存划分为若干个不同的数据区域。这些数据区域各有各的用处,各有各的创建与销毁时间,有的区域随着JVM进程的启动而存在,有的区域则依赖用户线程的启动和结束而创建与销毁。一般来说,JVM所管理的内存将会包含以下几个运行时数据区域
线程私有区域:程序计数器、Java虚拟机栈、本地方法栈线程共享区域:Java堆、方法区、运行时常量池

2.1.1程序计数器(线程私有)
程序计数器是一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。
如果当前线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是一个Native方法,这个计数器值为空。
程序计数器内存区域是唯一一个在JVM规范中没有规定任何OOM情况的区域!
什么是线程私有?
由于JVM的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现,因此在任何一个确定的时刻,一个处理 器(多核处理器则指的是一个内核)都只会执行一条线程中的指令。因此为了切换线程后能恢复到正确的执行位置,每 条线程都需要独立的程序计数器,各条线程之间计数器互不影响,独立存储。我们就把类似这类区域称之为"线程私 有"的内存。
2.1.2Java虚拟机栈(线程私有)
虚拟机栈描述的是Java方法执行的内存模型 : 每个方法执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈和出栈 的过程。声明周期与线程相同。
之前我们一直讲的栈区域实际上就是此处的虚拟机栈,再详细一点,是虚拟机栈中的局部变量表部分。
局部变量表 : 存放了编译器可知的各种基本数据类型(8大基本数据类型)、对象引用。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在执行期间不会 改变局部变量表大小。
此区域一共会产生以下两种异常:
1.如果线程请求的栈深度大于虚拟机所允许的深度(-Xss设置栈容量),将会抛出StackOverFlowError异常。
2.虚拟机在动态扩展时无法申请到足够的内存,会抛出OOM(OutOfMemoryError)异常
2.1.3本地方法栈(线程私有)

本地方法栈与虚拟机栈的作用完全一样,他俩的区别无非是本地方法栈为虚拟机使用的Native方法服务,而虚拟机栈为JVM执行的Java方法服务。
在HotSpot虚拟机中,本地方法栈与虚拟机栈是同一块内存区域。
2.1.4Java堆(线程共享)
Java堆( Java Heap)是JVM所管理的最大内存区域。Java堆是所有线程共享的一块区域,在JVM启动时创建。此内存区域存放的都是对象实例。JVM规范中说到:“所有的对象实例以及数组都要在堆上分配”。
Java堆是垃圾回收器管理的主要区域,因此很多时候可以称之为"GC堆"。根据JVM规范规定的内容,Java堆可以处于 物理上不连续的内存空间中。Java堆在主流的虚拟机中都是可扩展的(-Xmx设置最大值,-Xms设置最小值)。
如果在堆中没有足够的内存完成实例分配并且堆也无法再拓展时,将会抛出OOM
2.1.5方法区(线程共享)
方法区与Java堆一样,是各个线程共享的内存区域。它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。在JDK8以前的HotSpot虚拟机中,方法区也被称为"永久代"( JDK8已经被元空间取代)。
永久代并不意味着数据进入方法区就永久存在,此区域的内存回收主要是针对常量池的回收以及对类型的卸载。
JVM规范规定:当方法区无法满足内存分配需求时,将抛出OOM异常。
2.1.6运行时常量池(方法区的一部分)
运行时常量池是方法区的一部分,存放字面量与符号引用。
字面量 : 字符串( JDK1.7后移动到堆中) 、final常量、基本数据类型的值。
符号引用 : 类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符。
2.2Java堆溢出
Java堆用于存储对象实例,只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免来GC清除这些对象,那么在对象数量达到最大堆容量后就会产生内存溢出异常。
上节中已经讲到了,可以设置JVM参数-Xms:设置堆的最小值、-Xmx:设置堆最大值。下面我们来看一个Java堆OOM 的测试
范例:观察Java Heap OOM

Java堆内存的OOM异常是实际应用中最常见的内存溢出情况。当出现Java堆内存溢出时,异常堆栈信
息"java.lang.OutOfMemoryError"会进一步提示"Java heap space"。当出现"Java heap space"则很明确的告知我们,OOM发生在堆上。
此时要对Dump出来的文件进行分析,以MAT为例。分析问题的产生到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)
内存泄漏 : 泄漏对象无法被GC
内存溢出 : 内存对象确实还应该存活。此时要根据JVM堆参数与物理内存相比较检查是否还应该把JVM堆内存调大; 或者检查对象的生命周期是否过长。
以上是我们处理Java堆内存的简单方法,处理具体这类问题需要的工具以及知识我们放到下面第四小节具体来说。
2.3虚拟机栈和本地方法栈溢出
由于我们HotSpot虚拟机将虚拟机栈与本地方法栈合二为一,因此对于HotSpot来说,栈容量只需要由-Xss参数来设 置。
关于虚拟机栈会产生的两种异常:
如果线程请求的栈深度大于虚拟机所允许的最大深度,会抛出StackOverFlow异常 如果虚拟机在拓展栈时无法申请到足够的内存空间,则会抛出OOM异常
范例:观察StackOverFlow异常(单线程环境下)

出现StackOverflowError异常时有错误堆栈可以阅读,比较好找到问题所在。如果使用虚拟机默认参数,栈深度在多 多数情况下达到1000-2000完全没问题,对于正常的方法调用(包括递归),完全够用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值