JVM(1):jvm入门及最强GC垃圾回收算法详解

一、jvm解析

Java程序都是在JVM中运行, 实现了Java语言的跨平台性。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的,Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码,class文件),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令来执行。这就是Java的能够“一次编译,到处运行”的原因。

二、jVM体系结构

jvm可以执行多种语言,

每种语言都有一套规范。

java语言是一套规范,java虚拟机是一套规范。

java语言编译之后就变成了字节码文件,可以在jvm上面运行。

 

为什么要将jvm进行分区?

分区:方便管理。

jvm体系结构详解:

1、程序计数器

程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。

【注】:每个线程都应该有一个,属于线程私有

2、Java 虚拟机栈

它描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame )用于存储局部变量表、操作栈、动态链接、方法出口等信息。

与程序计数器一样,Java 虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,如果不是私有的话,就会把多个线程的方法都进入同一个栈,显然是不可能的。,它的生命周期与线程相同,即在线程创建时创建,线程结束时栈内存也随之释放。

3、本地方法栈

本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法(c或c++使用)服务。

4、Java 堆(jdk1.8后常量池在堆里)

此内存区域的唯一目的就是存放对象实例

一个JVM实例只存在一个堆,堆内存的大小是可以调节的。类加载器加载了类文件之后,需要把类放到堆内存中,以便执行器执行。

堆内存是线程共享的。

5、方法区

方法区(Method Area)与Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、静态变量、即时编译器编译后的代码等数据。

 

三、垃圾回收机制(GC)

首先,我们需要思考的几个问题?

  • 什么是GC?
  • Why need GC?
  • 哪些内存需要回收?
  • 什么时候回收?

 

3.1 现实内存管理和自动内存管理

显式内存管理(C/C++)

内存管理是程序开发者的职责

显示管理常见问题

内存泄露:内存空间已经申请,使用完毕后未主动释放。会一直占用内存。

野指针:使用了一个指针,但是该指针指向的内存空间已经被Free释放掉。指向了个未知的区域

自动内存管理(Java /C#/ 一些脚本语言)

内存空间是由一个叫做垃圾回收器的程序自动管理

优点:

       增加了程序的可靠性,减小了memory leak的情况、提高了程序猿的效率。

缺点:

       程序猿无法控制GC的时间,system.gc();

       判断哪些内存需要回收需要耗费系统开销

       逻辑上的内存泄露依然会存在

 

 3.2什么是GC

GC ——Garbage Collection

GC的工作原理:

       找出不再使用的对象( Garbage ),进行回收( Collection )

什么是垃圾:

          所有不再使用的对象都是垃圾

         不能在访问的对象就是垃圾

常见判断垃圾方法:

         引用计数法

         根搜索算法

 

3.2.1GC算法——引用计数法

引用计数法:(通过判断对象的引用对用来决定对象是否可以被回收)

给堆中的每一个对象增加一个引用计数器,当每一次创建一个对象并赋值给一个变量是,引用计数器就加1.当对象不再使用时(出了作用域),引用计数机减一。一但引用计数器为0,对象就满足了垃圾回收的条件

特点:

实现简单

缺点

无法解决循环引用问题(内存溢出)

对象的引用计数器的频繁更新,性能低

可能会出现线程安全问题

3.2.2 GC算法——根搜索算法(标记算法)

根搜索算法(Root Tracing)

在主流的商用程序处理语言中(hotswap),都是使用根搜索算法来判断对象是否存活的。

该算法的基本思路就是通过一系列的名为GC Root的对象作为起始点,从这些节点开始向下搜索,搜索所走的路径称为引用链(Reference chain)。当一个对象到所有的GC root之间没有任何引用链相连(用图论的话来说就是没GC roots到这些对象不可达)时,证明该对象是不可用的,GC程序即可回收这些对象。

 

就是在栈中作为root节点,然后依次引用堆内存的对象,如果没有跟栈节点相连接的,就看为垃圾,可以回收。

GC roots

  • 虚拟机栈中的引用对象
  • 方法区中的静态属性引用的对象
  • 方法区中常量引用的对象

 

专业术语:shallow size、retained size

Shallow size 就是对象本身占用的内存大小,也就是对象头加成员变量占用内存大小的总和

Retained size 是该对象自己的shallow size 加上仅可以从该对象访问(直接或者间接访问)的对象的shallow size之和。

Retained size是该对象被GC之后所能回收的内存的总和。

(蓝色部分为Retained size)

 

 

四、垃圾回收算法

  • 标记清除算法
  • 标记整理算法
  • 标记复制算法
  • 分代收集算法

 

4.1标记清除算法

JVM 和 Dalvik(Android 虚拟机)使用Mark Sweep算法实现垃圾回收(Android5.0之前的虚拟机 之后ART)

1)mark:标记出被引用的对象

2)Sweep:清除那些没有任何引用的对象

 

 

缺点

1.会产生空间碎片,创建大对象(大数组或者大字符串)就会出现,空间大小足够,但是不能创建成功

2.创建对象会比较慢。

 4.2  标记整理算法

适合场景:垃圾比较少的情况

优点:不会产生内存空间碎片

缺点:耗时

 

 

4.3 标记复制算法:

适合场景:存活对象比较少的情况

优点:不会产生碎片

缺点:浪费空间

4.4 分代收集算法

就是标记整理和标记复制的综合方法,所以在真实环境中用的正是该算法

jdk1.8之前,它首先将堆分为了几个不同的区域:

但是jdk1.8(包括1.8)之后,就没有永久代了!!!

1、新生代:尽可能快速的收集掉那些生命周期短的对象

分为:Eden区和两块的Survivor区,两个survivor复制有用对象到对方的内存中。依次迭代到某个值15,变成老年代

2、老年代:存放生命周期较长的对象

Full GC和Minor GC

触发FullGC的条件:

  1.        新生代出现大对象,直接存入老年代,然而老年代的空间也不足时触发。
  2.        调用System.gc()
  3.        jdk1.7之前的永久代空间不足

3、永久代

怎么理解呢?就比如一个老板娘开了个客栈,每天都有很多客人在那居住,租一两天的那种短租的客人是最多的,他们被称为是新生代;而也有部分人在那和老板娘一言不合就签下一两年合同的人,他们属于常驻客,也就是老年代,而如果你把老板娘的女儿娶了,那么你就是他们家人了,就是传说中的永久代!

【注意】

1.新生代默认是经过16次GC依然存活的对象就会变成老年代。

2.大对象:可以直接是老年代。

所以针对不同的区域采取不同的措施:

       新生代:会产生大量垃圾。-->标记复制算法

      老年代: 产生的垃圾比较少。--->标记整理算法

常用的调优参数:

-XX:SurvivorRatio:Eden和Survivor的比值,默认是8:1

-XX:NewRatio:老年代和年轻代内存大小的比较

-XX:Max:GC迭代次数的阈值

五、GC触发的时机

1.申请堆空间失败后会进行GC回收

2.系统进入idle后一段时间会进行回收

3.主动调用GC进行回收

 

六、常见的垃圾收集器

【知识前提】

JVM有两种运行模式Server与Client。

两种模式的区别在于,Client模式启动速度较快,Server模式启动较慢;

年轻代:

1.Serial收集器

      特点:

  • 单线程收集,必须暂停所有工作线程
  • 简单高效,Client模式下默认的年轻代收集器

2.ParNew收集器

  特点:多线程收集

3.Paraller Scavenge收集器

特点:

  • 更关注系统的吞吐量
  • Server模式下默认的年轻代收集器

老年代

1.Serial old收集器(单线程)

2.Paraller old(多线程,吞吐量优先)

3.CMS收集器:(一边丢垃圾,一边清除)标记清除算法。会产生碎片

4.Garbage First:(并发和并行)

 

优秀博文推荐:

https://juejin.im/post/5ae450b9f265da0b9a69b903

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值