JVM内部一目了然

首先我们带着这几个额问题来读这篇文章,可能收获会更大哦

1.请你谈谈你对JVM的理解?java8虚拟机和之前的变化更新?
​
2.什么是OOM,什么是栈溢出StackOverFlowError?怎么分析?
​
3.JVM的常用调优参数有哪些?
​
4.内存快照如何抓取,怎么分析Dump文件?知道吗?
​
5.谈谈在JVM中,你对类加载器的认识?

1.JVM提供了三总类加载器

1)根类加载器(使用C++编写,程序员无法在Java代码中或得该类)

2)扩展加载器,使用Java代码实现

3)系统加载器(应用加载器),使用java代码实现

JVM的内部结构:

 注意:父子加载器并非继承关系,也就是说子加载器不一定是继承父加载器。(双亲委派机制)

2.类的加载,连接(验证、准备、解析)与初始化,整个详细过程如图。

       类的加载指的是将类的 .class 文件中的二进制数据读入到内存中,将其放在运行时数据去的方法区内,然后再兑取创建一个java.lang.Class 对象,用来封装类在方法区内的数据结构。类加载器的作用:

它防止恶意代码去干涉善意的代码; //加载器双亲委派机制(为了安全)

它守护了被新人的类库边界;

它将代码归入保护域,确定了代码可以进行哪些操作。

一个Java类文件的具体加载过程如下:

 

3.我们可以自己实现自定义加载器:用户自定义的类加载器

• java.lang.ClassLoader的子类

• 用户可以定制类的加载方式

4.PC寄存器:每个线程都有一个程序计数器,是线程私有的,就是一个指针。

5.方法区:(static, final,Class,常量池)方法区是被所有的线程共享,此区域属于共享区间,静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法区无关。

6.主动使用六种

– 创建类的实例

– 访问某个类或接口的静态变量,或者对该静态变量赋值

– 调用类的静态方法

– 反射(如Class.forName(“com.itgwl.Test”)

– 初始化一个类的子类

– Java虚拟机启动时被标明为启动类的类(Java Test)

• 除了以上六种情况,其他使用Java类的方式都被看作是对类的被动使用,都不会导致类的初始化。注意:程序中对子类的“主动使用”会导致父类被初始化,但对父类的“主动”使用并不会导致子类的初始化。

7.栈

栈:栈内存,主管安程序的运行,生命周期和线程同步;

线程结束,栈内存也就释放,对于栈来说,不存在垃圾回收问题。

一旦线程结束,栈就Over!

栈:8大基本类型 + 对象引用 + 实例的方法

栈运行原理:栈帧( 父帧、子帧)

栈满了:StackOverflowError

栈+堆+方法区:交互关系

8.

实际上我们有多种JVM,1.Sun公司 HotSpot(TM) 64-bit Server VM(目前我们所用的就是这个版本)

2.BEA JRockit

3.IMB J9 VM

我们就来详细了解下堆:

Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的。

类加载器读取了类文件后,一般会把什么东西放到堆中?类,方法,常量,变量~保存我们所有引用类型的真实对象;

堆内存中分为三个区域:

新生区(伊甸园区) Young/New

养老区 Old

永久区 Perm

GC垃圾回收,主要是在伊甸园区和养老区~

假设内存满了,OOM,堆内存不够! Java.lang.OutOfMemoryError:java heap space,在JDK8以后,永久存储区改了个名字(元空间)

新生区

1.类:诞生和成长的地方,甚至死亡!

2.伊甸园,所有的对象都是在伊甸园区new出来的!

3.幸存者区(0,1)

真理:经过研究,99%的对象都是临时对象!

养老区

当一个对象经理了15次GC,都还没有销毁,默认15次 MaxTenuringThreshold=15(默认)

通过这个参数可以设定进入老年代的时间,就会从幸存区转入到老年区


永久区(元空间)

这个区域常驻内存。用来存放JDK自身携带的Class对象。Interfacce元数据,存储的是Java运行时的一些环境或类信息~,这个区域不存在垃圾回收!关闭VM虚拟机就回释放这个区域的内存~

一个启动类,加载类大量的第三方Jar包。Tomcat部署了太多的应用,大量动态生成的反射类。不断的被加载。知道内存满,就会出现OOM;

jdk1.6之前:永久代,常量用来存放是在方法区;
​
jdk1.7 : 永久代,但是慢慢的退化了,‘去永久代’ ,常量池在中
​
jdk1.8之后:无永久代,常量池在元空间,在方法区中的常量池。

//出现OOM怎么办呢?

1.尝试扩大堆内存看结果,如果还出现问题,肯定是代码出现问题了。

2.分析内存,看一下哪个地方出现了问题,调节JVM内存大小并打印GC的详细信息:-Xms1024m -Xmx1024m -XX:+PrintGCDetails

元空间:逻辑上存在,物理上不存在

一个项目中,突然出现了OOM故障,那么该如何排除~

能够看到代码第几行出错:内存快照分析工具,Eclipse 的MAT,Jprofiler

Dubug,一行行分析代码!

MAT,Jprofiler作用

1.分析Dump内存文件,快速定位内存泄漏;

2.获得堆中的数据

3.获得大的对象

//设置内存调优参数

// -Xms 设置初始化内存分配大小,默认为物理内存的 1/64

// -Xmx 设置最大分配内存,默认为物理内存的 1/4

//-XX:+PrintDCDetails //打印GC垃圾回收信息

// -XX:+HeadDumpOnOutofMemoryError //oom DUMP

//-Xms1m -Xmx8m -XX:HeapDumpOnOutMemoryError

GC:垃圾回收机制

JVM在进行GC时,并不是对这三个区域统一回收,大部分时候,回收都是新生代~

1.新生代 2.幸存区(from,to) 3.老年区

GC两种类:轻GC(普通的GC),重GC(全局GC)

题目:

1.JVM的内存模型和分区~ 详细到每个区放什么?

2.堆里面的分区有哪些? Eden,form,to,老年区,说说他们的特点!

3.GC的算法有哪些? 标记清除法,标记压缩,复制算法,引用计数器,怎么用的?

4.轻GC和重GC分别在什么时候发生?

GC常用算法

1.引用计数器(引用则+1,用完则-1)

2.复制算法(Copying):每次GC都会把EDen活的对象一道幸存区中:一旦Eden区被GC后,就会是空的!

谁空谁是to(from,to)

当一个对象经理了15次GC,都还没有销毁, -XX: -XX:MaxTenuringThreshold=15(默认)

通过这个参数可以设定进入老年代的时间

优点:没有内存的碎片

缺点:浪费了内存空间~ 多了一半空间永远是空to,假设对象100%存活

复制算法最爱使用场景:对象存活度较低的时候:新生区~

3.标记清除算法(Mark and Sweep)

扫描这些对象:对或者对象进行标记

清除:对没有标记的对象,进行清除

优点:不需要额外的空间!

缺点:两次扫描,严重浪费时间,会产生内存碎片。

4.可达性分析算法

通过判断对象的引用链是否可达来决定对象是否可以被回收。

总结:

内存效率:复制算法>标记清除算法>标记压缩算法

内存整齐度:复制算法=标记压缩算法>标记清除算法

内存利用率:标记压缩算法=标记清除算法>复制算法

思考一个问题:难道没有最有算法吗?

答案:没有,没有最好的算法,只有最合适的算法----》 GC:最合适就是利用分代收集算法

年轻代:存活率低,复制算法!

老年代:

区域大:存活率

标记清除(内存碎片不是太多)+标记压缩混合实现

谢谢,看到底部!如果本文对你有用,希望点个赞加关注!如有错误的地方,请指出来,方便进行改正,一起奥利给!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值