jvm总结

目录

1、什么情况下会发生堆、栈内存溢出。

2、JVM的内存结构,Eden和Survivor比例。

3、JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。

4、JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代

5、讲下cms和G1,包括原理,流程,优缺点。

6、JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作 内存等。

7、简单说说你了解的类加载器,可以打破双亲委派么,怎么打破。

8、讲讲JAVA的反射机制。


1、什么情况下会发生堆、栈内存溢出。

栈溢出:方法执行时创建的栈帧超过了栈的深度 ,最有可能就是方法递归调用。

堆溢出:heap space表示堆空间,堆中主要存储的是对象。不断的new对象会导致堆中的空间溢出

2、JVM的内存结构,Eden和Survivor比例。

JVM区域总体分两类,heap区和非heap区。
heap区又分为:

Eden Space(伊甸园)、
Survivor Space(幸存者区)、
Old Gen(老年代)。
非heap区又分:

Code Cache(代码缓存区);
Perm Gen(永久代);(jdk1.8为元空间)
Jvm Stack(java虚拟机栈);
Local Method Statck(本地方法栈);
 1个Eden区和2个Survivor区(分别叫from和to)。默认比例为8:1

3、JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。

首先说如果没有Survivor区会出现什么情况:此时每触发一次Minor GC,就会把Eden区的对象复制到老年代,这样当老年代满了之后会触发Major Gc(通常伴随着MinorGC,可以看做Full GC),比较耗时。

如果只有1个Survivor区,那当Eden区满了之后,就会复制对象到Survivor区,容易产生内存碎片化。严重影响性能。
所以使用2个Survivor区,始终保持有一个空的Survivor区,可以避免内存碎片化。

Survivor减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历多次Minor GC还能在新生代中存活的对象,才会被送到老年代。

4、JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代


对象诞生即新生代->eden,使用标记-清除垃圾回收算法,在进行minor gc过程中,如果依旧存活,移动到Survivor,进行标记代数,这里有两块survivor内存,通过复制算法,从根节点遍历,然后将遍历标记的复制到另外一个空的survivor中,并且回收之前的survivor区数据,survivor区默认长到15代之后,晋升为老年代,在老年代使用CMS收集器,依次进行初始标记、并发标记、重新标记、并发清除。当老年代满了之后会触发Major Gc(通常伴随着MinorGC,可以看做Full GC)

5、讲下cms和G1,包括原理,流程,优缺点。

CMS:
一、初始标记:快速遍历gc roots节点
二、并发标记:跟踪gc roots
三、重新标记:标记那些并发进程中未被标记的
四、并发清除:

缺点:cms基于标记清除的算法实现的,所以内存碎片会产生过多。

G1收集器:

 1、初始标记

 2、并发标记

3、最终标记

4、筛选回收

基于标记-整理算法,不产生内存碎片

二者区别

G1收集器收集范围是老年代和新生代。不需要结合其他收集器使用;

CMS收集器是老年代的收集器,在新生代需要配合Serial和ParNew收集器一起使用

6、JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作 内存等。

  • 重排序:为了提高性能,编译器和处理器会对执行进行重拍 
  • 主内存:共享变量存储的区域即是主内存 
  • 工作内存:每个线程copy的本地内存,存储了该线程读/写共享变量的副本 

7、简单说说你了解的类加载器,可以打破双亲委派么,怎么打破。

类加载器 就是根据指定全限定名称将class文件加载到JVM内存,转为Class对象。

启动类加载器(Bootstrap ClassLoader):负责加载 JAVA_HOME\lib 目录中的, 或通过-Xbootclasspath 参数指定路径中的, 且被虚拟机认可(按文件名识别, 如 rt.jar) 的类。
扩展类加载器(Extension ClassLoader):负责加载 JAVA_HOME\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类

应用程序类加载器(Application ClassLoader):负责加载用户路径(classpath)上的类库

双亲委派:当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父
类去完成,当父类加载器反馈自己无法完成这个请求的时候,子类加载器才会尝试自己去加载

打破: 

1:自己写一个类加载器集成classload

2:重写loadclass方法

3:重写findclass方法

8、讲讲JAVA的反射机制。

Java程序在运行状态可以动态的获取类的所有属性和方法,并实例化该类,调用方法的功能 

关于JAVA内存模型,一个对象(两个属性,四个方法)实例化100次,现在内存中的存储状态,几个对象,几个属性,几个方法。

由于JAVA中new出来的对象都是放在堆中,所以如果要实例化100次,将在堆中产生100个对象,一般对象与其中的属性、方法都属于一个整体,但如果 属性和方法是静态的,就是用static关键字声明的,那么属于类的属性和方法永远只在内存中存在一份。

线程私有区域

程序计数器:记录的是正在执行的虚拟机字节码指令的地址。所以它的长度是固定的,因此程序计数器内存区域是唯一一个在JVM规范中没有规定任何 OOM情况的区域。

Java虚拟机栈 

本地方法栈 : 本地方法栈为虚拟机使用的Native方法服务

线程共享区域

Java堆

永久区:静态变量,

在运行时常量池中(永久区的一部分):final修饰

GC ROOTS(根搜索算法)

作为GC Roots的对象:虚拟机栈引用、永久代引用、本地方法栈引用

频繁GC的原因:

人为原因:System.gc()、创建太多弱引用类;

框架原因:框架内部调用了GC方法;

内存原因:heap大小设置比较小时,会引起频繁的GC

优化GC的配置

-XX:NewRatio=3:设置新生代:老年代=1:3

-XX:SurvivorRatio=8:设置新生代中Eden:Survivor=8:1

-Xms6144M -Xmx6144M:初始化堆内存大小、最大堆内存大小

-XX:PermSize=128M -XX:MaxPermSize=256M:永久代内存大小、最大永久代大小。

jconsole查看内存使用情况

java反编译

javap -c Swap.class

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值