JVM
2023-07-27 22:57:44 54 举报
AI智能生成
JVM基础知识
作者其他创作
大纲/内容
双亲委派模型
为了保证不重复加载同一个类
JVM在加载类时会从下向上寻找有没有类加载器加载过
如果都没有,则会从上往下开始逐一尝试加载该类,如果可以加载则直接加载,否则抛出异常通知子类进行加载
启动类加载器BootstrapClassLoader是native方法,C语言实现的
类加载器
在创建一个类的实例对象前,JVM会去检查这个类是否已经被加载,如果没有则先加载类,才能创建实例
通过new关键字将class变为实例对象
通过实例对象的getClass方法将实例对象转回class
通过getClassLoader获取类的加载器
BootstrapLoader根加载器
ExtensionClassLoader扩展类加载器,一般加载JDK类库中的类
ApplicationClassLoader应用程序类加载器,一般我们自己编写的代码都由它加载
还可以自定义类加载器,通过继承ClassLoader
native
被native关键字修饰的方法,都是底层C语言实现的方法,要通过本地方法接口调用本地方法库
native方法进的是运行时数据区中的本地方法栈
JNI(Java Native Interface)目的是为了让JAVA可以融合不同的语言,扩展JAVA的使用
栈
一种先进后出FILO的数据结构
StackOverFlow就是压入栈中的方法太多了,超出栈的大小了
栈内存与线程声明周期同步,线程结束了栈也消失了
栈存储的主要是:对象引用,八大基本类型,实例方法
Hospot虚拟机
现在JDK基本都是Hospot虚拟机
以前是的JVM是JRockit实现
IBM的J9VM也是虚拟机的一种实现,只能在特定场合使用
GC垃圾回收
GC的扫描和回收的区域就是堆
常用算法
引用计数器
给每个对象分配一个计数器,统计有每个对象被持有的数量,每次清除没有引用被持有的对象(现在已经看不到这个算法了,效率低下)
复制
一旦minorGC过之后,Eden区为空,存活的对象就会被复制到S区,S0和S1,缺点是空间利用率低,只有百分之50,优点是没有内存碎片
最佳使用场景是对象存活率较低的地方,也就是Eden区
标记-整理
先标记,在清除,在整理,缺点:耗时,优点没有内存碎片,适合老年代回收
标记-清除
先做一次出初始标记,标记没有被引用的对象,Stop the world
并发标记,不暂停程序,多线程标记
最终标记,Stop the world暂停应用程序进行最终标记,确定哪些对象要被回收
清除被标记的对象,缺点内存碎片、耗时,优点空间利用率高
JMM
JAVA内存模型,一种标准,定义了Java原文件到字节码文件需要遵守的规范
类似于CPU的缓存一致性协议,定义了数据读写的规则
定义了线程的工作区域和主内存之间的抽象关系
JVM的位置
JVM运行上操作系统层之上,应用程序层之下,JAVA正是因为有了JVM,才具有跨平台能力,JAVA源文件需要通过JVM转译后运行
JAVA程序运行必须要有JRE(JAVA Runtime Environment),JDK是开发包,其中包含有JRE。
JVM体系结构
.java文件通过javac编译为.class文件
通过类加载器加载到JVM运行时数据区中的方法区
运行时数据区的组成
方法区
堆
栈
本地方法栈
程序计数器
JVM调优就是对堆和方法区的调整
沙箱安全机制
JAVA安全模型的核心就是JAVA沙箱
沙箱将JAVA代码限定在JVM的特定运行范围中,并且限制了代码对本地资源的访问
通过沙箱去隔离代码,防止非本地代码对本地资源进行破坏
如果远程代码必须要访问,则需要通过安全策略,用户指定代码对本地资源的访问权限
JDK1.2又新加入了代码签名,代码会根据用户的安全策略,将代码加载到不同的权限组中,实现不同代码的差异控制
JDK1.6后引入域机制,将代码加载到系统域或应用域中,系统域负责与本地资源及操作系统交流,应用域则通过系统域的代理来对资源进行访问
不同的域都有自己各自的权限
沙箱的基本条件
字节码校验器,检验java文件是否遵守java语言规范
类加载器,防止恶意代码干涉善意代码,守护了被信任类库的边界,将代码归入保护域,确定代码可以进行什么操作
虚拟机为不同类加载器载入的类提供不同的命名空间,每一个被加载的类都会有一个JVM维护的唯一名字,类相互之间不可见
双亲委派机制保证了恶意同名类无法被加载
存取控制器,可以控制核心API对操作系统的存取权限
安全管理器,核心API和操作系统之间的主要接口,控制权限,高于存储控制器
安全软件包,允许用户添加安全特性及提供安全特性。签名,加密,鉴别,摘要等
方法区
被所有线程共享,里面存储所有字段及类的字节码文件,一些特殊方法如构造函数、接口,所有定义的方法信息都在这
静态变量、常量、类的元数据,运行时常量池,字符串常量池也都在方法区
堆
一个JVM只有一个堆区,每个线程都会有一个栈
堆内存的大小可以通过参数调整
存储对象的实例,垃圾收集器扫描的主要区域,如果堆内存满了,并且垃圾收集器释放不了任何对象,就会OOM
新生代
Eden
被创建的对象实例一开始都在Eden
Eden与Survivor的默认比例是 8 :1
S0
如果某个对象活过了第一次垃圾收集,那么就会加入S0
S1
GC收集的复制算法,在GC收集S0时会复制并整理不会被收集的对象实例到S1,然后在清除整个S0
老年代
对象每活过一次GC,年龄都会+1,一旦年龄达到了老年代的门槛(15次GC没被回收),就会加入老年代
当老年代满了之后,JVM就会出发FullGC,扫描整个堆进行垃圾回收
一般情况下只会进行轻量级GC,minor GC
永久代
JDK8之前叫永久代,JDK8之后叫元空间,他们的区别就是元空间在直接内存中,不在JVM运行时内存中
JDK8后常量池转移到了元空间中
JDK1.7开始常量池已经在堆中了
主要存储JDK自身携带的class对象,interface元数据,运行时环境
JProfiler工具分析OOM原因
内存快照分析工具去快速查看OOM出现在哪,以及出现原因
分析DUMP内存文件,快速定位错误位置
获取堆中的数据,获取内存中的大对象信息
添加-XX:+HeapDumpOnOutofMemoryError JVM参数,当出现OOM时导出DUMP文件
Dump文件可以在项目路径下看到,后缀为.hprof
内存调优
-Xms 调节初始化内存大小
-Xmx 调节JVM最大内存大小
-XX:+HeapDumpOnOutofMemoryError
-XX:+PrintGCDetails
-XX:MaxTenuringThreshod 升级到老年代的门槛次数
0 条评论
下一页