JVM相关内容介绍

1定义

JVM:指定Java虚拟机的工作的规范。 但实现提供程序是独立的选择算法。 其实现是由Sun和其他公司提供。
它的实现被称为JRE(Java运行时环境)。
运行时实例只要在命令提示符上编写java命令来运行java类,就会创建JVM的实例。

2 组成成分

组件接收作用
类加载器-classLoaderJVM子系统加载类文件
运行时数据区(Runtime Data Area)内存区域,存储 运行时数据,包含1.方法区2.虚拟机栈3.本地方法栈4.堆5.程序计数器把字节码加载到内存中
执行引擎(Execution Engine)包含了:  虚拟处理器解释器:读取字节码流,然后执行指令。  即时(JIT)编译器:它用于提高性能,JIT编译的同时有类似字节代码部分的功能,从而减少编译所需的时间。  编译器是指从Java虚拟机(JVM)的指令集到特定CPU的指令集的转换器。将字节码翻译成底层系统指令
本地库接口(Native Interface)程序执行中需要访问本地方法库,通过本地库接口实现JAVA程序访问本地方法库的窗口

运行过程:

  1. 类加载器将 Java 代码转换成字节码
  2. 运行时数据区把字节码加载到内存
  3. 字节码文件 JVM 的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器执行引擎,将字节码翻译成底层系统指令,再交由 CPU 去执行
  4. 调用其他语言的本地库接口实现整个程序功能。

2.1JVM运行时数据区

JVM

组件共享/私有说明
共享1.JVM内存中最大,虚拟机启动时创建,所有线程共享。2.存放对象实例,几乎所有的对象实例和数组都在这里分配内存。3.堆是Java垃圾收集器管理的主要区域(GC堆),垃圾收集器实现了对象的自动销毁4.堆内存划分:新生代(新生代又分为Eden80%,Survivor20%)和老年代(Old),并且一般新生代的空间比老年代大。5.Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。6.可通过-Xmx和-Xms控制
方法区共享1.方法区也叫永久代Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java 堆区分开来.2.存储已被类加载的类信息,常量,静态变量以及编译器编译后的数据3.此区域的内存回收主要针对常量池的回收以及对类型的卸载4.JDK1.8以后成为元空间(Meta Space).方法区无法满足内存分配时会抛出OOM异常
虚拟机栈私有1.栈帧存储局部变量表,操作数栈,动态链接,方法返回地址和一些额外的符加信息。2.程序执行时入栈;执行完成后栈帧出栈。
本地方法栈私有包含应用程序中使用的所有本地方法
程序计数器私有指示当前程序执行到了哪一行,执行Java方法时记录正在执行的虚拟机字节码指令地址;执行本地方法时,计数器值为null

3 JVM 垃圾回收机制(GC)

垃圾回收指的是JVM在空闲时间不定时的回收无任何对象引用的对象所占的空间(不是对象本身)。可以说是垃圾回收只会负责释放那些对象占有的内存。对象比较抽象,它指的是引用和其占据的内存空间。当对象没有任何引用时其占据的内存空间随即被收回备用,此时对象也就被销毁,但不能说是回收对象。
概述:

  1. 引用:某个对象实例的内存地址在其他地方被存储使用
  2. 垃圾:无任何对象引用的对象
  3. 回收:清理“垃圾”占据的内存空间,

3.1 确定垃圾对象

3.1.1 引入计算法
此算法是每个对象创建一个引用计数,有对象引用时计数器+1,引用被释放时计数-1,当计数器为0时就可以被回收。
优点:引用计数收集器执行简单,判定效率高,交织在程序运行中。对程序不被长时间打断的实时环境比较有利(OC的内存管理使用该算法)。
缺点:难以检测出对象之间的循环引用。同时,引用计数器增加了程序执行的开销。所以Java语言并没有选择这种算法进行垃圾回收。
3.1.2 可达性分析法

此算法通过一系列被称为“GC Roots”的对象作为起点,从这些节点开始向下搜索对象,搜索过的路径,称为“引用链”,当一个对象到任意一个GC Roots对象没有任何作用的引用链相连时(从GC Roots对象不可达),证明此对象已死。
可作为GC Roots的对象包括以下场景:

  1. 虚拟机栈中的引用对象。
  2. 类静态变量引用的对象。
  3. 方法中的常量引用的对象。
  4. 本地方法栈中本地方法引用的对象。

在这里插入图片描述

obj8、obj9、obj10都没有到GCRoots对象的引用链,即便obj9和obj10之间有引用链,他们还是会被当成垃圾处理,可以进行回收.

3.2 垃圾回收算法

算法说明优点缺点
标记清除先标记,统一回收简单效率低,易产生内存碎片,导致大对象无法存储
复制内存一分为二,一半使用,一半用于复制存活对象解决标记-清除算法效率低下的问题,减少内存碎片内存利用率只有一半
标记-整理先标记,然后让存活对象向一端移动,最后统一回收既解决了复制算法内存利用率低的问题,又减少了标记-清除算法空间碎片的产生增加了存活对象移动的开销
分代根据对象生命周期对划分内存,分别采用合适的算法回收效率高,内存使用率也高内部实现较为复杂,需要合理划分内存

4.JVM 堆区域

堆的定义:堆是应用程序在运行期请求操作系统分配给自己的向高地址扩展的数据结构,是不连续的内存区域。
堆的组成:堆内存是由存活和死亡的对象组成的

  1. 存活的对象是应用可以访问的,不会被垃圾回收。
  2. 死亡的对象是应用不可访问的、尚且还没有被垃圾收集器回收掉的对象。一直到垃圾收集器把这些对象回收掉之前,他们会一直占据堆内存空间。

堆的作用:程序运行时动态申请某个大小的内存空间。
在这里插入图片描述

创建对象的内存分配过程
在这里插入图片描述

5.GC参数

参数作用
-XX:+DisableExplicitGC禁用显示 GC。
-Xms初始堆大小。 如:-Xms256m
-Xmx最大堆大小。 如:-Xmx512m
-Xmn新生代大小。通常为Xmx的1/3或1/4。新生代 = Eden + 2个Survivor空间。实际可用空间 = Eden + 1个Survivor,即90%
-XX:NewRatio新生代与老年代的比例。如-XX:NewRatio = 2 ,则新生代占整个空间的1/3,老年代占2/3。
-XX:SurvivorRatio新生代中Eden与Survivor的比值,默认为8。即Eden占新生代空间的8/10,另外两个Survivor各占1/10。
-XX:PermSize永久代(方法区)的初始大小
-XX:MaxPermSize永久代(方法区)的最大值
-XX:+PrintGCDetails打印GC信息

JVM相关的JAVA性能优化

  1. 减少new对象。每次new对象之后,都要开辟新的内存空间。这些对象不被引用之后,还要回收掉。因此,如果最大限度地合理重用对象,或者使用基本数据类型替代对象,都有助于节省内存;
  2. 多使用局部变量,减少使用静态变量。局部变量被创建在栈中,存取速度快。静态变量则是在堆内存;
  3. 避免使用finalize,该方法会给GC增添很大的负担;
  4. 如果是单线程,尽量使用非多线程安全的,因为线程安全来自于同步机制,同步机制会降低性能。例如,单线程程序,能使用HashMap,就不要用HashTable。同理,尽量减少使用synchronized
  5. 用移位符号替代乘除号。eg:a*8应该写作a<<3
  6. 对于经常反复使用的对象使用缓存;
  7. 尽量使用基本类型而不是包装类型,尽量使用一维数组而不是二维数组;
  8. 尽量使用final修饰符,final表示不可修改,访问效率高
  9. 单线程情况下(或者是针对于局部变量),字符串尽量使用StringBuilder,比StringBuffer要快;
  10. String为什么慢?因为String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象。如果不能保证线程安全,尽量使用StringBuffer来连接字符串。这里需要注意的是,StringBuffer的默认缓存容量是16个字符,如果超过16,apend方法调用私有的expandCapacity()方法,来保证足够的缓存容量。因此,如果可以预设StringBuffer的容量,避免append再去扩展容量。如果可以保证线程安全,就是用StringBuilder。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值