JVM深入理解

一 基本概念

JVM基本结构:


1、java的内存空间:
1)方法区:各线程共享的区域,存放类信息、常量、静态变量。
2)java堆:线程共享区域,存放类的实例,java堆空间是最大的,java堆空间不足,抛出OutOfMemoryError异常
3)java栈:线程的私有区域,生命周期与线程相同,一个线程就是一个java栈,每执行一个方法就会往栈中压入一个元素,这个元素叫做“栈帧”,栈帧包含了方法中的局部变量、用于存放中间状态值的操作栈;java的栈空间不足会抛出StackOverflowError异常(递归)
4)本地方法栈:与java栈类似,但是是用来表示执行本地方法,本地方法栈存放的方法调用本地方法接口,最终调用本地方法库,实现与操作系统、硬件交互的目的。
2、PC寄存器:
java类已经加载结束啦,程序的执行以及执行顺序就是PC寄存器再管,作用就是控制程序指令执行的顺序
3、执行引擎:

根据PC寄存器调配的指令顺序,依次执行程序指令


二 内存中线程的通讯

1、java内存定义的八种操作
1)lock(锁定):作用于主内存的变量,它把一个变量标识为一个线程独占的状态
2)unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
3)read(读取):作用于主内存的变量,它把一个变量的值从主内存传送到线程中的工作内存,以便随后的load动作使用
4)load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
5)use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎
6)assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存中的变量
7)store(存储):作用于工作内存的变量,它把工作内存中的一个变量的值传送到主内存中,以便随后的write操作

8)write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值写入主内存的变量中

2、通讯过程


3、volatile变量规则
1)保证变量的可见性

2)屏蔽指令重排序


三 配置参数
1、使用方法:在Eclipse中可以通过Run As|Run Configurations|Arguments|VM Arguments进行设置。
1)跟踪参数说明:
(1)-XX:+PrintGC或-verbose:gc:发生GC时打印简要信息
示例信息:[GC (Allocation Failure) 32686K->1648K(123904K), 0.0007230 secs]
32686K表示回收前,对象占用空间。1648K表示回收后,对象占用空间。123904K表示还有多少空间可用。0.0007230 secs表示这次垃圾回收花的时间。
(2)-XX:+PrintGCDetails:打印GC的详细信息以及堆使用详细信息
堆分为新生代(新生代的垃圾回收算法是采用复制算法)、老年代、元空间。注意这里没有永久区了,永久区在java8已经移除,原来放在永久区的常量、字符串静态变量都移到了元空间,并使用本地内存。
新生代当中又分为伊甸区(eden)和幸存区(from和to)
(3)-XX:+TraceClassLoading:监控java程序加载的类
(4)-Xloggc:log/gc.log:使用外部文件记录GC日志
2)堆配置参数说明
(1)Xmx、Xms:最大堆,最小堆
(2)Xmn:指定新生代内存大小
(3)-XX:NewRatio:新生代(eden+from+to)和老年代(不包含永久区)的比值

(4)-XX:SurvivorRatio(如设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10):Eden区与Survivor区(from、to)的大小比值


四 垃圾回收算法
1)说明:JVM在执行垃圾回收是时,会暂停当前的应用程序,等垃圾回收完成后,再继续执行
注意:垃圾回收时为什么要暂停当前的用用程序?
保证 java 标记清除时不会有新的对象产生(例子:如果在标记结束后,有新的对象产生,但是这个对象错过了标记期,那么在接下来的清楚过程中,由于这个新的对象没有被标记,所以被视为不可达对象而被清楚,就会导致程序出错)
2)种类:
(1)引用计数法:对一个对象被引用的次数进行计数,当增加一个引用计数就加1,减少一个引用计数就减1
特点:是最原始的回收算法,但是java中并没有采用这种算法,原因有:1、频繁的计数功能影响性能,2、无法处理循环引用的问题
(2)标记清除:
标记:遍历所有的GC Roots,并将从GC Roots可达的对象设置为存活对象;
清除:遍历堆中的所有对象,将没有被标记可达的对象清除;
特点:1 涉及大量的内存遍历工作,导致执行性能降低,也会导致java的程序暂停时间过长,java程序的吞吐量减低
2 对象被清除之后,被清除的对象留下内存空缺位置,造成内存不连续,空间浪费
(3)标记压缩:在标记清楚的基础上,增加了压缩过程
特点:1 在标记清除之后,对内存空间进行压缩,节省了内存空间,解决了标记清楚算法内存不连续的问题
2 标记压缩算法也会产生 java 应用程序的暂停,不能和java程序并发执行,压缩过程中一些对象的内存地址会发生改变,java程序只能等压缩完成之后才能继续执行
(4)复制算法:把内存一分为二,只是使用其中一份,在垃圾回收时,将正在使用的那份内存中的存活对象复制到另一份空杯内存中,最后将正在使用的空间对象清除,完成垃圾回收
特点:1 复制算法更加简洁高效
2 不适用与存活对象多的情况,复制的对象多,复制的性能差,因此一般用于内存中新生代的垃圾回收

3 内存空间占用成本高,因为是记忆两份内存空间做对象复制,垃圾回收器只用到了一个内从空间,内存利用率降低



五 垃圾回收器
1)说明:JVM的垃圾回收主要是针对以上堆空间的垃圾回收,当然其实也会针对元数据区(永久区)进行垃圾回收
2)几种垃圾回收器:
(1)串行收集器:-XX:+UseSerialGC
执行垃圾回收时,应用程序线程暂停,GC线程开始(开始垃圾回收),垃圾回收完成后,应用程序线程继续执行。注意:在GC线程运行过程中使用单线程进行串行回收。
(2)并行回收器:
a、 ParNew回收器:只针对新生代记性并发回收,老年代依然使用串行回收,新生代使用复制算法,老年代使用压缩算法(-XX:+UseParNewGC   -XX:ParallelGCThreads(指定并发线程数))
b、 Parallel回收器:类似于ParNew :新生代使用并行回收,老年代使用串行回收,与ParNew 不同在于设计目标上更注重吞吐量
-XX:+UseParallelGC
Parallel回收器另外一种配置则不同于ParNew,对于新生代和老年代均适应并行回收,要使用这种回收器可以在启动程序中配置:
XX:+UseParallelOldGC

(3)GMS回收器(Concurrent Mark Sweep,并发标记清除。这里注意两个词:并发、标记清除):-XX:+UseConcMarkSweepGC
过程:a、初始标记:标记从GC Root可以直接可达的对象
b:并发标记(和应用线程一起):主要标记过程,标记全部对象
c:重新标记:由于并发标记时,用户线程依然运行,因此在正式清理前,再做依次重新标记,进行修正
d:并发标记(和用户线程一起):基于标记结果,直接清理对象。
特点:a、减少了应用程序的停顿时间,回收线程与应用程序线程可以并发执行

b、运行机制导致他不可以像其他的回收器一样集中一段时间对垃圾进行回收,并且在回收时程序还是在运行,因此回收时不彻底的,导致相比于其他的回收器回收频率较高,影响应用程序的吞吐量


(4)G1回收器(G1回收器是jdk1.7以后推出的回收器,试图取代CMS回收器):-XX:+UseG1GC
特点:对比于CMS
a、因为划分了很多区块,回收时减少了内存碎片的产生
b、G1适用于新生代和老年代,CMS只适用于老年代
(5)回收器配置总结:
-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:+UseParNewGC:在新生代使用并行收集器
-XX:+UseParallelGC :新生代使用并行回收收集器,更加关注吞吐量
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:ParallelGCThreads:设置用于垃圾回收的线程数
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:设定CMS的线程数量

-XX:+UseG1GC:启用G1垃圾回收器


六 类加载原理

1)类加载流程:见图 类加载流程.png


(1)类的加载:我们平时所说的加载并不是指类的加载机制,只是加载机制中的第一步,在这个阶段 JVM主要完成三件事:
a、通过一个类的全限定名(包名与类名)来获取指定的二进制字节流(class文件)
b、将这个字节流代表的静态存储结构转化为方法区的运行时数据结构,只是进行数据结构的转换,并未合并数据
c、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的访问入口
(2)类的连接:
a、验证(文件格式验证、元数据验证、字节码验证、符号引用验证):判断class文件的合法性,比如class文件是不是以0xCAFEBABE开头,另外对版本号也会做验证
b、准备:为静态变量(static filed)在方法区中分配内存,并附默认初值0
       一般的成员变量是在类实例化,随对象一起分配在堆内存中
                       静态常量(static final field)会在准备阶段赋程序设定的初值;例如static final a=100,在准备阶段就会设置为100
c、解析:将类的二进制数据中的符号引用转化为直接引用
(3)类的初始化:为静态变量赋程序设定的初始值
2)类加载器:
(1)分类:
a、Bootstrap ClassLoader:启动类加载器,它负责加载Java的核心类库,加载如(%JAVA_HOME%/lib)目录下的rt.jar(包含System、String这样的核心类)这样的核心类库,不是java.lang.ClassLoader的子类,使用c/c++实现的
b、Extension ClassLoader:扩展类加载器,它负责加载扩展目录(%JAVA_HOME%/jre/lib/ext)下的jar包,用户可以把自己开发的类打包成jar包放在这个目录下即可扩展核心类以外的新功能
c、System ClassLoader\APP ClassLoader:系统类加载器或称为应用程序类加载器,是加载CLASSPATH环境变量所指定的jar包与类路径。一般来说,用户自定义的类就是由APP ClassLoader加载的
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值