JVM知识点总结(待续)

JVM知识点总结(待续),第1张

JVM知识点总结(待续)

JVM体系结构:*

加载器:
作用:将javac编译好的class文件装入虚拟机。
宏观来看,只有两种类加载器:启动类加载器、其他类加载器。

启动类加载器属于虚拟机的一部分,它是用C++写的,看不到源码;其他类加载器是用Java写的,说白了就是一些Java类,一会儿就可以看到了,比如扩展类加载器、应用类加载器。
启动类加载器:BootstrapClassLoader
扩展类加载器:ExtentionClassLoader
应用类加载器:AppClassLoader (也叫做“系统类加载器”)
既然只是把class文件装进虚拟机,为什么要用多种加载器呢?因为Java虚拟机启动的时候,并不会一次性加载所有的class文件(内存会爆),而是根据需要去动态加载。
不同的类加载器加载的内容:
类加载器是通过类的全限定名(或者说绝对路径)来找到一个class文件的。
启动类加载器加载的是jre和jre/lib目录下的核心库
扩展类加载器加载的是jre/lib/ext目录下的扩展包
应用类加载器加载的是java工程的bin目录
双亲委派机制:
有一个描述类加载器加载类过程的术语:双亲委派模型。然而这是一个很有误导性的术语,它应该叫做单亲委派模型(Parent-Delegation Model)。但是没有办法,大家都已经这样叫了。所谓双亲委派,这个亲就是指ClassLoader里的全局变量parent,也就是父加载器。

双亲委派的具体过程如下:

当一个类加载器接收到类加载任务时,先查缓存里有没有,如果没有,将任务委托给它的父加载器去执行。
父加载器也做同样的事情,一层一层往上委托,直到最顶层的启动类加载器为止。
如果启动类加载器没有找到所需加载的类,便将此加载任务退回给下一级类加载器去执行,而下一级的类加载器也做同样的事情。
如果最底层类加载器仍然没有找到所需要的class文件,则抛出异常。
所以是一条线传上再传下,并没有什么“双亲”。

为什么要双亲委派?
确保类的全局唯一性。

如果你自己写的一个类与核心类库中的类重名,会发现这个类可以被正常编译,但永远无法被加载运行。因为你写的这个类不会被应用类加载器加载,而是被委托到顶层,被启动类加载器在核心类库中找到了。如果没有双亲委托机制来确保类的全局唯一性,谁都可以编写一个java.lang.Object类放在classpath下,那应用程序就乱套了。

从安全的角度讲,通过双亲委托机制,Java虚拟机总是先从最可信的Java核心API查找类型,可以防止不可信的类假扮被信任的类对系统造成危害。
参考链接:

https://zhuanlan.zhihu.com/p/73359363

native:
凡是带有native关键字的,说明Java的作用范围达不到,回去调用底层C语言库,
会进入本地方法栈,调用本地方法接口JNI(JNI的作用:扩展Java的使用,融合不同编程语言为Java所用!)它在内存区域中专门开辟了一块标记区域:Native method Stock,登记native方法,在最终执行的时候,加载本地方法库中的方法通过JNI。结合JVM结构图来分析。
方法区:
方法区:静态变量,常量,类信息,运行时的常量池(static,final,Class,常量池)

栈: 栈内存主管程序运行,生命周期和线程同步;线程结束,栈内存释放。
栈:8大基本类型+对象引用+实例的方法
栈运行的原理:栈帧
栈溢出会报错:StackOverflowError
堆: 实例对象
Java对象在内存中实例化的全过程:
参考博客链接:

https://blog.csdn.net/Tony__Jaa/article/details/107612059
https://blog.csdn.net/weixin_46037153/article/details/104427109
https://www.cnblogs.com/Cerpelus/p/14654273.html

堆内存:
关于堆内存的区域的划分:
如何理解元空间(jDK8之后)逻辑上存在和物理上不存在,
逻辑上分区是新生区,老年区,元空间。但是运行程序会发现,新生区占用的内存+老年区占用的内存等于总内存。
默认情况下:分配的总内存是电脑内存的1/4,而初始化的内存为分配总内存的1/16.

JVM调整堆内存的大小:
	编辑run:
	-Xms1024m -Xmx1024m -XX:+PrintGCDetails  //打印垃圾回收信息
    -Xms 设置初始化内存分配大小 ,默认电脑内存的1/64
    -Xmx 设置最大分配内存大小,默认电脑内存的1/4
OOM(OutOfMemoryError)问题如何解决: 
	1.尝试扩大堆内存
	2.分析内存,查看哪个地方出现了问题
	编辑run:
    -Xms8m -Xmx8m -XX:+HeapDumponOutOfMemoryError  //oom DUMP

IDEA中安装Jprofile插件,并且在安装桌面版的Jprofile,然后settings中设置如下。

打开生成的快照文件。查看堆遍历器中biggest Object 和 占用的线程,找出问题所在的行。

GC题目:
JVM的内存模型和分区 详细到每个分区放什么?
堆里面的分区有哪些?新生区(伊甸园(Eden),幸存区(from, to)) 老年区,以及他们的特点!(谁空谁是to区)
GC算法有哪些?标记清除法,标记压缩法,复制算法,引用计算器,怎么使用?
答案:
引用计数算法:主要是标记
复制算法:主要是复制from区到to区,保证to区为空。

优点:没有内存碎片,
缺点:浪费内存空间:多了一半的内存空间为空 to区;假设对象100%存活(极端情况)
因此复制算法应用的最佳场景:对象存活度较低,新生区。
标记清除压缩算法:

标记清除算法:
优点:不需要额外的空间 ,缺点:两次扫描严重浪费时间,会产生内存碎片。

标记压缩算法:
优点:防止压缩碎片的产生,缺点:多了一次移动成本
总结:
从内存效率:复制算法>标记清楚算法>标记压缩算法(时间复杂度)
内存整齐度:复制算法=标记压缩算法>标记清楚算法
内存利用率:标记压缩算法=标记清楚算法>复制算法
没有最优的算法只有最合适的算法 :分代收集算法
对于年轻代:存活率低,复制算法
对于老年代:区域大,存活率高,采用标记清楚+标记压缩混合算法

轻GC和重GC分别 发生在什么时候?
新生代内存不够用时候发生 MGC 也叫 YGC,JVM 内存不够的时候发生 FGC。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5637255.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存