关于JVM的一些问题

1、什么是JVM内存结构?

在这里插入图片描述

JVM将虚拟机分为五大区域,程序计数器、虚拟机栈、本地方法栈、java堆、方法区。
1·程序计数器:线程是私有的,是一块很小的内存空间,作为当前线程的行号指示器,用于记录当前虚拟机正在执行的线程指令地址。
2·虚拟机栈:线程是私有的,每个方法执行的时候都会创建一个栈帧,用于储存局部变量表、操作数、动态链接和方法返回等信息,当线程请求的栈深度超过了虚拟机允许的最大深度时就会抛出StackOverFlowError。
3·本地方法栈:线程是私有的,保存的是native方法信息,当一个jvm创建的线程是调用native方法后,jvm不会在虚拟机栈为该线程创建栈帧,而是简单的动态链接并直接调用该方法。
4·堆:java堆是所有线程共享的一块内存,几乎所有对象的实例和数组都需要在堆上分配内存,因此在区域会经常发生垃圾处理操作。
5·方法区:存放类加载、常量、静态变量、即时编译器编译后的代码数据,但是在jdk1.8之后就不存在方法区了,被元数据区代替了,原方法区被分为两部分:一是加载的类信息,二是运时常量池。加载的类信息保存在元数据区,运行常量池保存在堆中。

2、heap和stack有什么区别?

1·申请方式
stack:由系统自动分配。比如,在函数中一个局部变量 int a,系统会自动在栈中为a开辟空间。
heap:需要程序员自己申请,并指明大小。比如,在函数中需要new Object()的形式自己开辟。
2·申请后系统的响应
stack:只要栈的剩余空间大于申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
heap:操作系统有一个记录空闲内存地址的链表,当系统收到程序申请时,会遍历该链表,寻找第一个空间大于该申请空间的堆节点,然后把这个节点从空闲节点中删除,并把该节点空间分配给程序。另外,由于找到的节点空间大小不一定大小刚好等于所需空间大小,所以系统会将多余的部分重新加入空闲链表。
3·申请大小的限制
stack:栈是向低地址扩展的数据结构,是一块连续的内存区域,所以栈顶的地址和栈的最大容量都是系统预先预定好的,在Windows下,栈的大小是2M,所以能从栈获取的空间较小。
heap:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统用链表来储存空闲内存地址的,所以是不连续的,而链表的遍历方向是由低到高的。堆的大小受限于计算机系统中有效的虚拟内存,所以堆的空间大小的是比较灵活,也比较大的。
4·申请效率的比较
stack:由系统制动分配,所以速度较快。但是无法由程序员自己控制。
heap:由new分配的内存,一般速度较慢,也会参数内存碎片,但是很方便。
5·储存内容
stack:在函数调用时,第一进入栈的是主函数的下一个指令的地址,然后是函数的各个参数,然后是局部变量。静态变量不能入栈。调用结束后,局部变量先出栈,然后是参数,最后是栈顶的指令。
heap:有程序员自行安排。

3、什么情况下会发生栈溢出?

当线程请求的栈深度超过了虚拟机允许的最大深度就会发生StackOverflowError异常,方法的递归肯定会出现该问题。

4、如何判断一个对象是否存活?

1·引用计数法
给对象中添加一个 引用计数器,每当有一个地方引用它时,计数器值+1,当引用失效时,计数器值-1。任何时刻计数器值为0的对象就是不可能再被使用的。但是这个方法有个问题不能解决:就是当两个对象相互引用时,他们的计数器值永远不会变成0,导致两个对象无法被回收,所以主流虚拟机都不采用这个方法。
2·可达性分析
基本思想是通过一系列被称之为”GC Roots“的根对象作为起始节点集,从这些根节点开始,根据引用关系向下搜索,搜索过程所走过的路径称之为”引用链“,如果一个对象到RC Roots没有任何引用链相连,则表明这个对象不可达。在java中可以作为GC Roots的对象有以下几种:
1、虚拟机栈(栈帧中的本地变量表)中的引用的对象。
2、方法区中的类静态属性引用的对象。
3、方法区中的常量引用的对象。
4、本地方法栈中JNI(Native方法)的引用的对象。

5、Java中的垃圾回收算法所有那些?

java中有四种垃圾回收算法:标记清除法、标记整理法、复制算法、分代收集法。
标记清除法
第一步:利用可达性遍历内存,把存活对象和垃圾对象进行标记。
第二步:在遍历一遍,把垃圾对象回收掉。
特点:效率不太好,标记和清除的效率都不太高,标记和清除后会产生大量的不连续的空间分片,可能会导致之后程序运行需要分配较大的对象而找不到储存空间而在进行一次GC。
标记整理法
第一步:利用可达性遍历内存,把存活对象和垃圾对象进行标记。
第二步:将所有存活对象向一端移动,把端边界以外的对象全部清除掉。
特点:适用于存货对象多,垃圾少的情况下,无空间碎片产生。
复制算法
将内存按照容量大小分为大小相等的两块,每次只使用一块,当一块使用完了,就把还存活着的对象转移到另一块,再把使用的内存清除。
特点:不会产生空间碎片,内存使用效率极低。
分代收集法
Java虚拟机一般将内存划分为新生代和老年代,在新生代中,有大量死去和少量存活对象,所以采用复制算法,因为只需要付出少量存活对象的复制成本就可以完成收集。老年代中存活对象占大多数,所以采用标记清除或整理法进行回收。

6、垃圾回收器

垃圾回收器主要分为以下几种:Serial、ParNew、Parallel Scavenge、Seral Old、Parallel Old、 GMS、G1;

Serial:单线程的收集器,收集垃圾时,必须stop the world ,使用复制算法。最大的特点是在进行垃圾回收时,需要对所有正在执行的程序暂停,对于大部分应用很难接受,但是如果对应用实用性不高的话,只要停顿时间在N毫秒内也是可以接受的。
ParNew:Serial收集器的多线程版本,也需要stop the world,使用复制算法。
Parallel Scavenge:新生代收集器,复制算法的收集器,并发多线程收集器。目标是达到一个可控的吞吐量,和ParNew的最大区别就是GC自动调节策略;虚拟机会根据系统运行状态收集性能监控信息,动态设置这些参数,来提供最优停顿时间和最大吞吐量。
Seral Old:是Serial的老年代版本,单线程收集,采用标记整理法。
Parallel Old:是Parallel Scavenge的老年代版本,使用多线程,采用标记整理算法。
GMS:是一种以获得最短回收停顿时间为目标的收集器,使用标记清除算法,运作过程:初始标记,并发标记,重新标记,并发清除,收集结束后会产生大量空间碎片。
G1:采用标记整理算法实现,运作过程:初始标记,并发标记,最终标记,筛选回收。不会产生大量空间碎片,可以精确控制停顿;G1将整个堆分为大小相等的多克Region ,G1跟踪每个区域的垃圾大小,在后台维护一个优先级列表,每次根据允许的收集时间,优先回收价值最大的区域,以达到在有限的时间获得最高的回收效率。
各个垃圾回收器的对比
在这里插入图片描述
垃圾回收器的配合使用图
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值