jvm学习笔记(一)

一、jvm内存模型

 

 

1.程序计数器:一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工的时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,他是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。没条线程都需要有一个独立的成熟计数器。

2.java虚拟机栈:与程序计数器一样,java虚拟机栈也是线程私有的每个方法被执行的时候,java虚拟机都会同步创建一个栈帧用于存储局部变量表、操作数栈、动态连接、方法出口信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机中从入栈到出栈的过程。

3.本地方法栈:本地方法栈与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行java方法(字节码)服务的。而本地方法栈则是为虚拟机使用到的本地方法(native)方法服务。

4.java堆:java堆是虚拟机所管理的内存中最大的一块,java堆是被所有线程共享的一块区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象。由于现代垃圾收集器大部分都是基于分代收集理论设计的,所以java堆中经常出现 “新生代”、“老年代” 、“永久代”、“endn空间”、“form survivor空间”、“To survivor”等名词。

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

5.1运行时常量池:运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一样信息是常量池表,用于存放编译期生成的各种字面量与符号引用,这部分内容加载后存放到方法区的运行时常量池中。运行旗舰也可以将新的常量放入池中,这种特性被开发人员利用的比较到的便是String类的intern()方法。

6、直接内存:直接内存并不是jvm内存模型的一部分,在jdk 1.4新加入了NIO类,引入了一种基于通道与缓存区的I/O方式,它可以使用native函数库直接分配堆外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作,这样能在一些场景中显著提高性能,因为避免了再java堆和native堆中来回复制数据。

二、对象的内存布局

在hotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头(hander)、实例数据(Instance Data)和对齐填充(Padding)。

HotSpot虚拟机对象的对象头部分包括两类信息。第一类是用于存储对象自身的运行时数据,如哈希码(hashcode)、GC分代年龄、锁状态标志,线程持有的锁、偏向线程ID、偏向时间戳等。

HotSpot虚拟机对象头 Mark word

存储内容

标记位

状态

对象哈希码、分代年龄

01

未锁定

指向锁记录的指针

00

轻量级锁定

指向重量级的指针

10

重量级锁

空,不需要记录信息

11

GC标记

偏向线程ID,偏向时间戳、对象分代年龄

01

可偏向

 

三、OutOfMemoryError异常

1.java堆溢出:

将堆最大内存(-Xmx)和最小内存(-Xms)设置一样 避免自动扩展 通过参数 -XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出的时候Dump出现当前的内存堆转储快照以便进行事后分析

设置参数:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

代码:创建大对象。

解决办法:检查代码 是否存在内存泄漏,设置堆参数(-Xms和-Xmx),检查代码中某些对象生命周期是否过长;

2.虚拟机栈和本地方法栈溢出:

由于HotSpot虚拟机中并不区分虚拟机栈和本地方法栈,因此对于HotSpot来说,栈容量只能由-Xss参数来设定。

1)如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

2)如果虚拟机的栈内存允许动态扩展,当扩展容量无法申请到足够的内存时,将抛出OutOfMemoryError异常,(HotSpot虚拟机不支持栈内存动态扩展)

设置参数:-Xss128k

代码:递归

如果不断的创建线程也可以导致OutOfMemoryError,所以给线程栈分配的内存越大,越容易产生内存溢出异常。

3.方法区和运行时常量池溢出

参数:-XX:PermSize=6M -XX:MaxPermSize=6M

代码:循环向集合添加String.intern();

此异常只会存在jdk6以下的版本,jdk7及以上版本不会在出现是因为自jdk7起原本放在永久代的字符串常量池被移至java堆中。

String str1 = new StringBuilder("计算机").append("软件").toString(); System.out.println(str1.intern()==str1); //true String str2 = new StringBuilder("ja").append("va").toString(); System.out.println(str2.intern()==str2); //false

jdk6中运行会得到两个false,而在JDK7中运行,会得到一个true和一个false,因为JDK6中intern()方法会把首次遇到的字符串示例复制到永久代的字符串常量池中存储,返回的意识永久代里面这个字符串实例的引用,而StringBuilder创建的字符串对象实例在java堆上,所以不是同一个引用。而jdk7中都是在就java堆中,但是“java”字符串并非第一次创建。

四、垃圾回收器

1.检查对象是否存活的算法:

1.1引用计数法:在对象中添加一个引用计数器,每当有引用时,计数器加1,引用失效计数器减一,但是无回收相互引用的对象。

1.2.可达性分析算法:GC Roots的根对象作为起始节点集,从这些节点开始根据引用向下搜索,搜索的路径称为引用链,如果某个对象到GC Roots 间没有引用链,则这个对象不可达。

GC Roots的对象包括以下几种

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
  • 在方法区中类静态属性引用的对象,譬如java类的引用类型静态变量。
  • 在方法区中常量引用的对象,譬如字符串常量池里的引用。
  • 在本地方法栈中JNI(native)引用的对象。
  • java虚拟机内部的引用,如基本数据乐行对应的Class对象,一些常驻的异常对象等,还有系统类加载器。
  • 所有被同步锁(synchronized 关键字)持有的对象
  • 反映java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

2.垃圾回收算法

2.1标记-清除算法:分标记、清除两个阶段。最早最基础的垃圾收集算法。主要缺点:一是执行效率不稳定,执行效率随对象数量增长而下降。第二个是内存空间碎片化问题。空间碎片太多可能会导致当以后在程序运行过程中需要分配大对象时无法找到足够连续内存而不得不提前触发另一次垃圾收集。

2.2标记-复制算法:为了解决标记清除算法面对大量可回收对象时执行效率低的问题,Fenichel提出了半区复制的算法,它将可用内存划分为等量大小的两块,显而易见,这种复制方式空间浪费太多,后IMB公司研究,新生代中的对象98%熬不过第一轮收集。现将内存分为Eden区和两块survivor区,比例为8:1;

2.3标记-整理算法:标记算法与 标记清除法一致;标记后让所有存活的对象都向内存空间一端移动,然后直接清除掉边界以外的内存。移动内存回收 则更加复杂

2.4分代收集理论:收集器应该将java堆分出不同的区域,然后回收对象依据其年龄分配到不同的区域之中存储。minor GC、Major GC、Full Gc

五、垃圾回收器:

1.Serial收集器:Serial收集器是最基础、最悠久的收集器,这个收集器是一个单线程工作的收集器,但它的“单线程”的意义并不仅仅是说明它只会使用一个处理器或者一条收集线程去完成工作,更重要的是强调在它进行垃圾收集时,必须暂停其他所有工作线程,直到它收集结束。

2.PerNew收集器:PerNew收集器实质上是Serial收集器的多线程并行版本。

3.Parallel Scavenge收集器:Parallel Scavenge的特点是他关注的点与其他收集器不同。CMS等收集器的关注点是尽可能的缩短垃圾收集时用户线程的停顿时间。而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量,Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集的停顿时间 -XX:MacGCPauseMillis参数以及直接设置吞吐量大小的 -XX:GCTimeRatio。

4.Serial Old 收集器:Serial Old收集器是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记-整理算法。它有两种用途:一种是在JDk5以及之前的版本中与Parallel Scavenge收集器搭配使用,另外一种就是作为CMS收集器发生失败时的后备预案。

5.Parallel Old收集器:Parallel Old是Parallel Scavenge收集器的老年代版本。支持多线程并发收集,基于标记-整理算法实现。这个收集器在jdk1.6才开始提供。

6.CMS收集器:CMS收集器是一种以获取最短回收停顿时间为目标的收集器。它的运作过程分为四个步骤,初始标记、并发标记、重新标记、并发清除。

7.Garbage First收集器:Garbage First(简称G1)收集器是垃圾收集器技术发展历史上的里程碑式的成果,它开创了收集器面向局部收集的设计思路和基于Region的内存布局形式,JDK7 Update4 Oracle才认为它达到足够成熟的商用程度,JDK8 Update40的时候,G1提供并发的类卸载的支持,这个版本以后的G1收集器才被Oracle官方称为“最全能的垃圾收集器”。JDK9发布之日,G1宣告取代Parallel Scavenge加Parallel Old组合,成为服务端模式下默认的垃圾收集器,而CMS则沦落至被声明为不推荐使用的收集器。

8.Shenandoah收集器:

9.ZGC收集器:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值