Jvm内存结构简析

jvm原理简析

1.什么是jvm?

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

引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

2.jvm内存结构、内存模型傻傻的分不清楚

2.1jvm内存结构

在这里插入图片描述如上图,我们平时所说的jvm内存结构主要是指运行时数据区。运行时数据区主要分为五个部分。
堆区:(其大小可以通过-Xmx和-Xms来控制)Java 堆是所有线程共享的,它在虚拟机启动时就会被创建。Java 堆是内存空间占据的最大一块区域了,Java 堆是用来存放对象实例及数组,也就是说我们代码中通过 new 关键字 new 出来的对象都存放在这里。
这里也是发生GC(下文会重点说明GC)的主要区域。
虚拟机栈
      1、 Java 虚拟机的每一条线程都有自己私有的 Java 虚拟机栈,这个 Java 虚拟机栈跟线程同时创建,所以它跟线程有相同的生命周期。

      2、Java 虚拟机栈描述的是 Java 方法执行的内存模型:每一个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中的入栈到出栈的过程。

      3、局部变量表存放了编译期可知的各种基本数据类型对象引用

     1、基本类型:八种基本类型   		
     2、对象引用:reference 类型,它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置。

方法区
      在 JDK1.7的时候,方法区被称作为永久代, 从JDK1.8开始,Metaspace (元空间)也就是我们所谓的方法区!
与Java堆一样,都是各个线程共享的,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
JDK8之后就没有永久代这一说法变成叫做元空间(meta space),而且将老年代与元空间剥离。元空间放置于本地的内存中,因此元空间的最大空间就是系统的内存空间了,从而不会再出现像永久代的内存溢出错误了,也不会出现泄漏的数据移到交换区这样的事情。用户可以为元空间设置一个可用空间最大值,不设置默认根据类的元数据大小动态增加元空间的容量。对于一个 64 位的服务器端 JVM 来说,其默认的–XX:MetaspaceSize 值为 21MB。也就是说默认的元空间大小是21MB。
本地方法栈
      和虚拟机栈相似,只不过它服务于Native方法,线程私有。当 Java 虚拟机使用其他语言(例如 C 语言)来实现指令集解释器时,也会使用到本地方法栈。如果 Java 虚拟机不支持 natvie 方法,并且自己也不依赖传统栈的话,可以无需支持本地方法栈。

与 Java 虚拟机栈一样,本地方法栈区域也会抛出 StackOverflowError 和 OutOfMemoryError 异常。

HotSpot虚拟机直接就把本地方法栈和虚拟机栈合二为一。
程序计数器
      当前线程所执行的字节码的行号指示器,用于记录正在执行的虚拟机字节指令地址,线程私有。
(唯一没有规定内存溢出的区域)

2.2 jvm内存模型

简单用一句话来概括:保证多线程之间操作共享变量的正确性!至于如何保证推荐阅读 https://www.jianshu.com/p/76959115d486

3. 垃圾回收机制(GC)

我们主要讲堆内存的回收。

3.1 堆内存结构划分

      堆大小 = 新生代 + 老年代。堆的大小可通过参数–Xms(堆的初始容量)、-Xmx(堆的最大容量) 来指定。
       其中,新生代 ( Young ) 被细分为 Eden 和 两个 Survivor 区域,这两个 Survivor 区域分别被命名为 from 和 to,以示区分。默认的,Edem : from : to = 8 : 1 : 1 。(可以通过参数 –XX:SurvivorRatio 来设定 。即: Eden = 8/10 的新生代空间大小,from = to = 1/10 的新生代空间大小。
JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的。
新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。

3.2 新生代、老年代回收算法

新生代:新生代的对象具有朝生夕死的特点,对象小而少,所以采用复制算法????小朋友,你是不是有很多问号?
复制算法简要过程
1)Eden 区活着的对象 + From Survivor 存储的对象被复制到 To Survivor

2)清空 Eden 和 From Survivor ;

3)颠倒 From Survivor 和 To Survivor 的逻辑关系: From 变 To , To 变 From 。
当对象较小时,copy所用的时间相对缩短,所以效率更高。但是代价是我们付出了10%的Survivor空间,典型的以空间换时间。

老年代:老年代的对象都是经历过无数次生死历程最终熬到了白头,所以不是那么容易死的。所以老年代会有较多的存活对象,那么就不能用复制算法,因为可能没有最够的空间去复制,会导致频繁的gc,所以老年代采用标记整理算法。
标记整理:对判定为死亡的对象进行标记,然后将存活的对象整理到一起,清除死亡对象,这样会减少内存碎片的产生。但是标记 整理的过程相对于复制算法耗时要长,但是节省了部分空间。以时间换空间。

关于如何判定对象是否可以被回收这里就不多说了,自行查找资料吧。

4. jvm性能调优

      jvm性能调优不是绝对的,还要结合实际情况。
      ①:增大jvm的内存大小,我们都知道频繁的gc对我们程序的运行影响很大,所以增大内存在一定程度上是可以提高效率的,但是并不是越大越好,在增大内存的同时导致每次GC的耗时也会随之增长。所以在增大jvm内存的同时,我们应控制好gc的频率,特别是Full GC,我们在创建对象时如果对象过大会直接进去永久代(jdk1.8改为元空间),这里我们可以通过设置jvm参数(-XX:PretrnureSizeThreshold)做相应的控制,尽量让对象先进入新生代,利用Minor GC尽快回收掉。
      ②:合理设置jvm参数与收集器,查看gc日志或使用开源jvm监控程序,分析原因,有针对性的解决问题。
推荐链接:https://my.oschina.net/LucasZhu/blog/2056232
开源工具:https://github.com/chewiebug/GCViewer
GC日志分析:https://blog.csdn.net/qq_21383435/article/details/80702205

5. 总结

未完待续。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值